feat(renderer): Implement getOrAcquire and remove methods in RendererWorkingSet interface and update RendererWorkingSetImpl
This commit is contained in:
@@ -2,7 +2,6 @@ package de.extio.game_engine.renderer.g2d;
|
|||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.EventQueue;
|
import java.awt.EventQueue;
|
||||||
import java.awt.Font;
|
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
import java.awt.Toolkit;
|
import java.awt.Toolkit;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
@@ -25,7 +24,6 @@ import org.slf4j.LoggerFactory;
|
|||||||
import de.extio.game_engine.module.AbstractClientModule;
|
import de.extio.game_engine.module.AbstractClientModule;
|
||||||
import de.extio.game_engine.renderer.Renderer;
|
import de.extio.game_engine.renderer.Renderer;
|
||||||
import de.extio.game_engine.renderer.RendererData;
|
import de.extio.game_engine.renderer.RendererData;
|
||||||
import de.extio.game_engine.renderer.g2d.G2DRenderer.G2DRendererModule;
|
|
||||||
import de.extio.game_engine.renderer.g2d.bo.rendering.G2DAbstractRenderingBo;
|
import de.extio.game_engine.renderer.g2d.bo.rendering.G2DAbstractRenderingBo;
|
||||||
import de.extio.game_engine.renderer.g2d.bo.rendering.G2DDrawBackground;
|
import de.extio.game_engine.renderer.g2d.bo.rendering.G2DDrawBackground;
|
||||||
import de.extio.game_engine.renderer.g2d.bo.rendering.G2DDrawFont;
|
import de.extio.game_engine.renderer.g2d.bo.rendering.G2DDrawFont;
|
||||||
@@ -54,6 +52,8 @@ public class G2DRenderer implements Renderer {
|
|||||||
|
|
||||||
private final List<RenderingBo> renderingBOs = new ArrayList<>();
|
private final List<RenderingBo> renderingBOs = new ArrayList<>();
|
||||||
|
|
||||||
|
private final Map<Class<? extends RenderingBo>, RenderingBo> usedRenderingBoTypes = new HashMap<>();
|
||||||
|
|
||||||
private volatile G2DMainFrame mainFrame;
|
private volatile G2DMainFrame mainFrame;
|
||||||
|
|
||||||
private String rendererModuleId;
|
private String rendererModuleId;
|
||||||
@@ -190,8 +190,10 @@ public class G2DRenderer implements Renderer {
|
|||||||
screenGraphics.setColor(Color.BLACK);
|
screenGraphics.setColor(Color.BLACK);
|
||||||
screenGraphics.fillRect(0, 0, viewPortDimension.getX(), viewPortDimension.getY());
|
screenGraphics.fillRect(0, 0, viewPortDimension.getX(), viewPortDimension.getY());
|
||||||
|
|
||||||
|
usedRenderingBoTypes.clear();
|
||||||
for (final RenderingBo renderingBO : this.renderingBOs) {
|
for (final RenderingBo renderingBO : this.renderingBOs) {
|
||||||
if (renderingBO instanceof final G2DAbstractRenderingBo g2dAbstractRenderingBo) {
|
if (renderingBO instanceof final G2DAbstractRenderingBo g2dAbstractRenderingBo) {
|
||||||
|
usedRenderingBoTypes.putIfAbsent(g2dAbstractRenderingBo.getClass(), g2dAbstractRenderingBo);
|
||||||
g2dAbstractRenderingBo.render(screenGraphics, this.rendererData.getRendererControl().getScaleFactor(), false);
|
g2dAbstractRenderingBo.render(screenGraphics, this.rendererData.getRendererControl().getScaleFactor(), false);
|
||||||
if (takeScreenshot_ && g2dAbstractRenderingBo.isScreenshotRelevant()) {
|
if (takeScreenshot_ && g2dAbstractRenderingBo.isScreenshotRelevant()) {
|
||||||
g2dAbstractRenderingBo.render(screenshotGraphics, this.rendererData.getRendererControl().getScaleFactor(), true);
|
g2dAbstractRenderingBo.render(screenshotGraphics, this.rendererData.getRendererControl().getScaleFactor(), true);
|
||||||
@@ -199,7 +201,9 @@ public class G2DRenderer implements Renderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.rendererData.getRendererWorkingSet().get(this.rendererModuleId, "G2DRenderer_tooltip").closeStatic();
|
for (final RenderingBo bo : usedRenderingBoTypes.values()) {
|
||||||
|
bo.closeStatic();
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Rendering cycle END
|
// Rendering cycle END
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ public interface RendererWorkingSet {
|
|||||||
<T extends RenderingBo> T get(String producerId, String id, Class<T> type);
|
<T extends RenderingBo> T get(String producerId, String id, Class<T> type);
|
||||||
|
|
||||||
<T extends RenderingBo> T getOrAcquire(String producerId, String id, Class<T> type);
|
<T extends RenderingBo> T getOrAcquire(String producerId, String id, Class<T> type);
|
||||||
|
|
||||||
|
void remove(String producerId, String id);
|
||||||
|
|
||||||
Map<String, RenderingBo> getUncommittedWork(String producerId);
|
Map<String, RenderingBo> getUncommittedWork(String producerId);
|
||||||
|
|
||||||
|
|||||||
@@ -31,22 +31,38 @@ public class RendererWorkingSetImpl implements RendererWorkingSet {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void put(final String producerId, final RenderingBo work) {
|
public void put(final String producerId, final RenderingBo work) {
|
||||||
this.getWorkingSetByProducer(producerId)
|
final var previous = this.getWorkingSetByProducer(producerId)
|
||||||
.next()
|
.next()
|
||||||
.put(work.getId(), work);
|
.put(work.getId(), work);
|
||||||
|
if (previous != null) {
|
||||||
|
this.rendererBoPool.release(previous);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void put(final String producerId, final List<RenderingBo> work) {
|
public void put(final String producerId, final List<RenderingBo> work) {
|
||||||
final var nextMap = this.getWorkingSetByProducer(producerId).next();
|
final var nextMap = this.getWorkingSetByProducer(producerId).next();
|
||||||
for (final RenderingBo bo : work) {
|
for (final RenderingBo bo : work) {
|
||||||
nextMap.put(bo.getId(), bo);
|
final var previous = nextMap.put(bo.getId(), bo);
|
||||||
|
if (previous != null) {
|
||||||
|
this.rendererBoPool.release(previous);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove(final String producerId, final String id) {
|
||||||
|
final var previous = this.getWorkingSetByProducer(producerId)
|
||||||
|
.next()
|
||||||
|
.remove(id);
|
||||||
|
if (previous != null) {
|
||||||
|
this.rendererBoPool.release(previous);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, RenderingBo> getUncommittedWork(final String producerId) {
|
public Map<String, RenderingBo> getUncommittedWork(final String producerId) {
|
||||||
return this.getWorkingSetByProducer(producerId).next();
|
return Map.copyOf(this.getWorkingSetByProducer(producerId).next());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -74,25 +90,26 @@ public class RendererWorkingSetImpl implements RendererWorkingSet {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, RenderingBo> commit(final String producerId, final boolean clone) {
|
public Map<String, RenderingBo> commit(final String producerId, final boolean clone) {
|
||||||
final AtomicReference<Map<String, RenderingBo>> previousWork = new AtomicReference<>();
|
final AtomicReference<Map<String, RenderingBo>> previousLiveRef = new AtomicReference<>();
|
||||||
final RendererWork rendererWork = this.workingSet.compute(producerId, (k, v) -> {
|
final RendererWork rendererWork = this.workingSet.compute(producerId, (k, v) -> {
|
||||||
if (v == null) {
|
if (v == null) {
|
||||||
return new RendererWork(this.obtainMapFromPool(), this.obtainMapFromPool());
|
return new RendererWork(this.obtainMapFromPool(), this.obtainMapFromPool());
|
||||||
}
|
}
|
||||||
previousWork.set(v.live());
|
previousLiveRef.set(v.live());
|
||||||
if (clone) {
|
if (clone) {
|
||||||
final Map<String, RenderingBo> newNext = this.obtainMapFromPool();
|
final Map<String, RenderingBo> newNext = this.obtainMapFromPool();
|
||||||
newNext.putAll(v.next());
|
newNext.putAll(v.next());
|
||||||
return new RendererWork(v.next(), newNext);
|
return new RendererWork(v.next(), newNext);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
v.live().values().forEach(this.rendererBoPool::release);
|
||||||
return new RendererWork(v.next(), this.obtainMapFromPool());
|
return new RendererWork(v.next(), this.obtainMapFromPool());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
final var previousWorkMap = previousWork.get();
|
final var previousLiveSet = previousLiveRef.get();
|
||||||
if (previousWorkMap != null) {
|
if (previousLiveSet != null) {
|
||||||
this.releaseBoClasses(previousWorkMap);
|
this.returnMapToPool(previousLiveSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
return rendererWork.next();
|
return rendererWork.next();
|
||||||
@@ -102,8 +119,8 @@ public class RendererWorkingSetImpl implements RendererWorkingSet {
|
|||||||
public void clear(final String producerId) {
|
public void clear(final String producerId) {
|
||||||
final RendererWork rendererWork = this.workingSet.remove(producerId);
|
final RendererWork rendererWork = this.workingSet.remove(producerId);
|
||||||
if (rendererWork != null) {
|
if (rendererWork != null) {
|
||||||
this.releaseBoClasses(rendererWork.live());
|
rendererWork.live().values().forEach(this.rendererBoPool::release);
|
||||||
this.releaseBoClasses(rendererWork.next());
|
rendererWork.next().values().forEach(this.rendererBoPool::release);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,23 +137,6 @@ public class RendererWorkingSetImpl implements RendererWorkingSet {
|
|||||||
return this.workingSet.computeIfAbsent(producerId, k -> new RendererWork(this.obtainMapFromPool(), this.obtainMapFromPool()));
|
return this.workingSet.computeIfAbsent(producerId, k -> new RendererWork(this.obtainMapFromPool(), this.obtainMapFromPool()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void releaseBoClasses(final Map<String, RenderingBo> work) {
|
|
||||||
if (work == null || work.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final var releasedBoClasses = this.obtainSetFromPool();
|
|
||||||
for (final RenderingBo renderingBO : work.values()) {
|
|
||||||
if (releasedBoClasses.add(renderingBO.getClass())) {
|
|
||||||
renderingBO.closeStatic();
|
|
||||||
}
|
|
||||||
this.rendererBoPool.release(renderingBO);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.returnMapToPool(work);
|
|
||||||
this.returnSetToPool(releasedBoClasses);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<String, RenderingBo> obtainMapFromPool() {
|
private Map<String, RenderingBo> obtainMapFromPool() {
|
||||||
var map = this.mapsPool.poll();
|
var map = this.mapsPool.poll();
|
||||||
if (map == null) {
|
if (map == null) {
|
||||||
@@ -150,19 +150,6 @@ public class RendererWorkingSetImpl implements RendererWorkingSet {
|
|||||||
this.mapsPool.offer(map);
|
this.mapsPool.offer(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<Class<? extends RenderingBo>> obtainSetFromPool() {
|
|
||||||
var set = this.setsPool.poll();
|
|
||||||
if (set == null) {
|
|
||||||
set = new HashSet<>();
|
|
||||||
}
|
|
||||||
return set;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void returnSetToPool(final Set<Class<? extends RenderingBo>> set) {
|
|
||||||
set.clear();
|
|
||||||
this.setsPool.offer(set);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static record RendererWork(Map<String, RenderingBo> live, Map<String, RenderingBo> next) {
|
private static record RendererWork(Map<String, RenderingBo> live, Map<String, RenderingBo> next) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@@ -85,8 +84,9 @@ public class RendererWorkingSetImplTest {
|
|||||||
final var returnedUncommitted = this.workingSet.commit(this.moduleA.getId(), false);
|
final var returnedUncommitted = this.workingSet.commit(this.moduleA.getId(), false);
|
||||||
final var currentUncommitted = this.workingSet.getUncommittedWork(this.moduleA.getId());
|
final var currentUncommitted = this.workingSet.getUncommittedWork(this.moduleA.getId());
|
||||||
|
|
||||||
assertSame(currentUncommitted, returnedUncommitted);
|
assertTrue(returnedUncommitted.isEmpty());
|
||||||
assertTrue(currentUncommitted.isEmpty());
|
assertTrue(currentUncommitted.isEmpty());
|
||||||
|
assertEquals(returnedUncommitted, currentUncommitted);
|
||||||
|
|
||||||
final List<RenderingBo> live = new ArrayList<>();
|
final List<RenderingBo> live = new ArrayList<>();
|
||||||
this.workingSet.getLiveSet(live, null);
|
this.workingSet.getLiveSet(live, null);
|
||||||
@@ -109,7 +109,7 @@ public class RendererWorkingSetImplTest {
|
|||||||
final var returnedUncommitted = this.workingSet.commit(this.moduleA.getId(), true);
|
final var returnedUncommitted = this.workingSet.commit(this.moduleA.getId(), true);
|
||||||
final var currentUncommitted = this.workingSet.getUncommittedWork(this.moduleA.getId());
|
final var currentUncommitted = this.workingSet.getUncommittedWork(this.moduleA.getId());
|
||||||
|
|
||||||
assertSame(currentUncommitted, returnedUncommitted);
|
assertEquals(currentUncommitted, returnedUncommitted);
|
||||||
assertEquals(Map.of("bo1", bo1, "bo2", bo2), currentUncommitted);
|
assertEquals(Map.of("bo1", bo1, "bo2", bo2), currentUncommitted);
|
||||||
|
|
||||||
final List<RenderingBo> live = new ArrayList<>();
|
final List<RenderingBo> live = new ArrayList<>();
|
||||||
@@ -186,8 +186,6 @@ public class RendererWorkingSetImplTest {
|
|||||||
|
|
||||||
verify(this.renderingBoPool, times(1)).release(bo1);
|
verify(this.renderingBoPool, times(1)).release(bo1);
|
||||||
verify(this.renderingBoPool, times(1)).release(bo2);
|
verify(this.renderingBoPool, times(1)).release(bo2);
|
||||||
assertEquals(1, bo1.closeStaticCalls());
|
|
||||||
assertEquals(1, bo2.closeStaticCalls());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -206,7 +204,7 @@ public class RendererWorkingSetImplTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void secondCommitReleasesPreviousLiveWorkAndCallsCloseStaticOncePerClass() {
|
void secondCommitReleasesPreviousLiveWork() {
|
||||||
final var bo1 = new TestBoA();
|
final var bo1 = new TestBoA();
|
||||||
bo1.setId("bo1");
|
bo1.setId("bo1");
|
||||||
final var bo2 = new TestBoA();
|
final var bo2 = new TestBoA();
|
||||||
@@ -223,11 +221,6 @@ public class RendererWorkingSetImplTest {
|
|||||||
|
|
||||||
verify(this.renderingBoPool, times(1)).release(bo1);
|
verify(this.renderingBoPool, times(1)).release(bo1);
|
||||||
verify(this.renderingBoPool, times(1)).release(bo2);
|
verify(this.renderingBoPool, times(1)).release(bo2);
|
||||||
|
|
||||||
// closeStatic() is called exactly once per class, so one of bo1 or bo2 has it called
|
|
||||||
final int totalCloseStaticCallsForTestBoA = bo1.closeStaticCalls() + bo2.closeStaticCalls();
|
|
||||||
assertEquals(1, totalCloseStaticCallsForTestBoA);
|
|
||||||
assertEquals(0, bo3.closeStaticCalls());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -362,8 +355,6 @@ public class RendererWorkingSetImplTest {
|
|||||||
|
|
||||||
private static abstract class TestBoBase implements RenderingBo {
|
private static abstract class TestBoBase implements RenderingBo {
|
||||||
|
|
||||||
private final AtomicInteger closeStaticCalls = new AtomicInteger();
|
|
||||||
|
|
||||||
private String id;
|
private String id;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -483,13 +474,9 @@ public class RendererWorkingSetImplTest {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void closeStatic() {
|
public void closeStatic() {
|
||||||
this.closeStaticCalls.incrementAndGet();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int closeStaticCalls() {
|
|
||||||
return this.closeStaticCalls.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setRendererData(final RendererData RendererData) {
|
public void setRendererData(final RendererData RendererData) {
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user