11.3.2021, 9:00 - 11:00: Due to updates GitLab may be unavailable for some minutes between 09:00 and 11:00.

Commit 376f75c4 authored by Benedikt Zoennchen's avatar Benedikt Zoennchen

OpenCL bug-fix: memory leaks.

parent 50d9ef0d
...@@ -11,63 +11,64 @@ import org.vadere.state.attributes.scenario.AttributesAgent; ...@@ -11,63 +11,64 @@ import org.vadere.state.attributes.scenario.AttributesAgent;
public class CLGaussianCalculator { public class CLGaussianCalculator {
private final double scale; private final double scale;
private final int scenarioWidth; private final int scenarioWidth;
private final int scenarioHeight; private final int scenarioHeight;
private SimulationModel<DefaultSimulationConfig> model; private SimulationModel<DefaultSimulationConfig> model;
private IGaussianFilter filterObstacles; private IGaussianFilter filterObstacles;
private IGaussianFilter filterPedestrians;
public CLGaussianCalculator(final SimulationModel model, public CLGaussianCalculator(final SimulationModel model,
final double scale, final double scale,
final double measurementRadius, final double measurementRadius,
final Color color, final Color color,
final boolean visualisation, final boolean visualisation,
final boolean scenarioBound) { final boolean scenarioBound) {
this.scenarioWidth = (int) model.getTopographyBound().getWidth(); this.scenarioWidth = (int) model.getTopographyBound().getWidth();
this.scenarioHeight = (int) model.getTopographyBound().getHeight(); this.scenarioHeight = (int) model.getTopographyBound().getHeight();
this.scale = scale; this.scale = scale;
this.model = model; this.model = model;
this.filterObstacles = IGaussianFilter.create(model.getTopography(), scale, model.getTopography().isBounded(), this.filterObstacles = IGaussianFilter.create(model.getTopography(), scale, model.getTopography().isBounded(),
0.7, IGaussianFilter.Type.OpenCL); 0.7, IGaussianFilter.Type.OpenCL);
} }
public BufferedImage getDensityImage() { public BufferedImage getDensityImage() {
IGaussianFilter filterPedestrians = IGaussianFilter.create( IGaussianFilter filterPedestrians = IGaussianFilter.create(
model.getTopography().getBounds(), model.getTopography().getBounds(),
model.getAgents(), model.getAgents(),
scale, scale,
0.7f, 0.7f,
new AttributesAgent(-1), new AttributesAgent(-1),
(ped) -> 1.0, (ped) -> 1.0,
IGaussianFilter.Type.OpenCL); IGaussianFilter.Type.OpenCL);
filterPedestrians.filterImage(); filterPedestrians.filterImage();
filterObstacles.filterImage(); filterObstacles.filterImage();
filterPedestrians.destroy();
return convertFilterToImage(filterPedestrians, filterObstacles);
}
return convertFilterToImage(filterPedestrians, filterObstacles); private BufferedImage convertFilterToImage(final IGaussianFilter filterPedestrians,
} final IGaussianFilter filterObstacles) {
int width = Math.max(filterObstacles.getMatrixWidth(), filterPedestrians.getMatrixWidth());
int height = Math.max(filterObstacles.getMatrixHeight(), filterPedestrians.getMatrixHeight());
BufferedImage image = createImage(width, height);
int maxColorValue = 255 * 255 * 255;
ColorHelper colorHelper = new ColorHelper(maxColorValue);
private BufferedImage convertFilterToImage(final IGaussianFilter filterPedestrians, // double bound = filter.getMaxFilteredValue();
final IGaussianFilter filterObstacles) { double max = 1.00;
int width = Math.max(filterObstacles.getMatrixWidth(), filterPedestrians.getMatrixWidth()); double factor = maxColorValue / max;
int height = Math.max(filterObstacles.getMatrixHeight(), filterPedestrians.getMatrixHeight()); System.out.println(filterPedestrians.getMaxFilteredValue()); // 0.1259
BufferedImage image = createImage(width, height);
int maxColorValue = 255 * 255 * 255;
ColorHelper colorHelper = new ColorHelper(maxColorValue);
// double max = filter.getMaxFilteredValue(); for (int x = 0; x < filterPedestrians.getMatrixWidth(); x++) {
double max = 1.00; for (int y = 0; y < filterPedestrians.getMatrixHeight(); y++) {
double factor = maxColorValue / max; double pedValue = filterPedestrians.getFilteredValue(x, y);
System.out.println(filterPedestrians.getMaxFilteredValue()); // 0.1259 double obsValue = filterObstacles.getFilteredValue(x, y);
double value = pedValue + obsValue;
for (int x = 0; x < filterPedestrians.getMatrixWidth(); x++) { // value = pedValue;
for (int y = 0; y < filterPedestrians.getMatrixHeight(); y++) { image.setRGB(x, y, colorHelper.numberToColor(value * factor).getRGB());
double pedValue = filterPedestrians.getFilteredValue(x, y);
double obsValue = filterObstacles.getFilteredValue(x, y);
double value = pedValue + obsValue;
// value = pedValue;
image.setRGB(x, y, colorHelper.numberToColor(value * factor).getRGB());
/* /*
* if(value <= 0.0) { * if(value <= 0.0) {
* image.setRGB(x, y, Color.WHITE.getRGB()); * image.setRGB(x, y, Color.WHITE.getRGB());
...@@ -75,20 +76,24 @@ public class CLGaussianCalculator { ...@@ -75,20 +76,24 @@ public class CLGaussianCalculator {
* image.setRGB(x, y, colorHelper.numberToColor(value * factor).getRGB()); * image.setRGB(x, y, colorHelper.numberToColor(value * factor).getRGB());
* } * }
*/ */
} }
} }
return image; return image;
} }
public void destroy() {
this.filterObstacles.destroy();
}
/** /**
* Helper method which create a new standard BufferedImage with the needed * Helper method which create a new standard BufferedImage with the needed
* configurations. * configurations.
* *
* @return the image which is prepared for additional drawing * @return the image which is prepared for additional drawing
*/ */
private BufferedImage createImage(final int width, final int height) { private BufferedImage createImage(final int width, final int height) {
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
return image; return image;
} }
} }
...@@ -7,6 +7,7 @@ import java.awt.Stroke; ...@@ -7,6 +7,7 @@ import java.awt.Stroke;
import java.awt.geom.Path2D; import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.util.Collection;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.apache.log4j.LogManager; import org.apache.log4j.LogManager;
...@@ -17,126 +18,133 @@ import org.vadere.gui.components.utils.ColorHelper; ...@@ -17,126 +18,133 @@ import org.vadere.gui.components.utils.ColorHelper;
import org.vadere.gui.components.utils.Resources; import org.vadere.gui.components.utils.Resources;
import org.vadere.state.scenario.Agent; import org.vadere.state.scenario.Agent;
import org.vadere.util.geometry.shapes.VPoint; import org.vadere.util.geometry.shapes.VPoint;
import org.vadere.util.geometry.shapes.VTriangle;
public abstract class SimulationRenderer extends DefaultRenderer { public abstract class SimulationRenderer extends DefaultRenderer {
private static Logger logger = LogManager.getLogger(SimulationRenderer.class); private static Logger logger = LogManager.getLogger(SimulationRenderer.class);
private static Resources resources = Resources.getInstance("postvisualization"); private static Resources resources = Resources.getInstance("postvisualization");
private static double MAX_POTENTIAL = 1000.0; private static double MAX_POTENTIAL = 1000.0;
private static double CONTOUR_STEP = 2.0; private static double CONTOUR_STEP = 2.0;
private static double CONTOUR_THINKNESS = 0.2; private static double CONTOUR_THINKNESS = 0.2;
private SimulationModel model; private SimulationModel model;
private BufferedImage obstacleDensity = null; private BufferedImage obstacleDensity = null;
private BufferedImage potentialFieldImage = null; private BufferedImage potentialFieldImage = null;
private ColorHelper colorHelper; private ColorHelper colorHelper;
private Color lastDensityColor = null; private Color lastDensityColor = null;
private int topographyId; private int topographyId;
public SimulationRenderer(final SimulationModel model) { public SimulationRenderer(final SimulationModel model) {
super(model); super(model);
this.model = model; this.model = model;
this.topographyId = -1; this.topographyId = -1;
this.colorHelper = new ColorHelper(40); this.colorHelper = new ColorHelper(40);
} }
@Override @Override
protected void renderPreTransformation(Graphics2D graphics2D, int width, int height) { protected void renderPreTransformation(Graphics2D graphics2D, int width, int height) {
if (model.isFloorFieldAvailable() && model.config.isShowPotentialField()) { if (model.isFloorFieldAvailable() && model.config.isShowPotentialField()) {
synchronized (model) { synchronized (model) {
renderPotentialField(graphics2D, renderPotentialField(graphics2D,
(int)(Math.min(model.getTopographyBound().width, model.getViewportBound().width) * model.getScaleFactor()), (int)(Math.min(model.getTopographyBound().width, model.getViewportBound().width) * model.getScaleFactor()),
(int)(Math.min(model.getTopographyBound().height, model.getViewportBound().height) * model.getScaleFactor())); (int)(Math.min(model.getTopographyBound().height, model.getViewportBound().height) * model.getScaleFactor()));
} }
} }
super.renderPreTransformation(graphics2D, width, height); super.renderPreTransformation(graphics2D, width, height);
} }
@Override @Override
public void renderPostTransformation(final Graphics2D graphics, final int width, final int height) { public void renderPostTransformation(final Graphics2D graphics, final int width, final int height) {
graphics.setColor(Color.BLACK); graphics.setColor(Color.BLACK);
// if there is no potential field than draw the default background (white) // if there is no potential field than draw the default background (white)
// otherwise do not overdraw the potential field!!! // otherwise do not overdraw the potential field!!!
if (!model.isFloorFieldAvailable() || !model.config.isShowPotentialField()) { if (!model.isFloorFieldAvailable() || !model.config.isShowPotentialField()) {
super.renderPostTransformation(graphics, width, height); super.renderPostTransformation(graphics, width, height);
} }
if (model.config.isShowDensity()) { if (model.config.isShowDensity()) {
renderDensity(graphics); renderDensity(graphics);
} }
if (model.config.isShowGrid()) { if (model.config.isShowGrid()) {
renderGrid(graphics); renderGrid(graphics);
} }
if (model.config.isShowObstacles()) { if (model.config.isShowObstacles()) {
renderScenarioElement(model.getTopography().getObstacles(), graphics, model.config.getObstacleColor()); renderScenarioElement(model.getTopography().getObstacles(), graphics, model.config.getObstacleColor());
} }
if (model.config.isShowStairs()) { if (model.config.isShowStairs()) {
renderScenarioElement(model.getTopography().getStairs(), graphics, model.config.getStairColor()); renderScenarioElement(model.getTopography().getStairs(), graphics, model.config.getStairColor());
} }
if (model.config.isShowTargets()) { if (model.config.isShowTargets()) {
renderScenarioElement(model.getTopography().getTargets(), graphics, model.config.getTargetColor()); renderScenarioElement(model.getTopography().getTargets(), graphics, model.config.getTargetColor());
} }
if (model.config.isShowSources()) { if (model.config.isShowSources()) {
renderScenarioElement(model.getTopography().getSources(), graphics, model.config.getSourceColor()); renderScenarioElement(model.getTopography().getSources(), graphics, model.config.getSourceColor());
} }
if (model.isVoronoiDiagramAvailable() && model.isVoronoiDiagramVisible()) { if (model.isVoronoiDiagramAvailable() && model.isVoronoiDiagramVisible()) {
renderVoronoiDiagram(graphics, model.getVoronoiDiagram()); renderVoronoiDiagram(graphics, model.getVoronoiDiagram());
} }
renderSimulationContent(graphics); renderSimulationContent(graphics);
if (model.isElementSelected()) { if (model.isElementSelected()) {
renderSelectionBorder(graphics); renderSelectionBorder(graphics);
} }
if (model.isSelectionVisible()) { if (model.isSelectionVisible()) {
renderSelectionShape(graphics); renderSelectionShape(graphics);
} }
if (hasLogo() && model.config.isShowLogo()) { if (hasLogo() && model.config.isShowLogo()) {
renderLogo(graphics, model.getScaleFactor(), height); renderLogo(graphics, model.getScaleFactor(), height);
} }
graphics.dispose(); graphics.dispose();
} }
protected void renderTrajectory(final Graphics2D g, final java.util.List<VPoint> points, final Agent pedestrain) { protected void renderTrajectory(final Graphics2D g, final java.util.List<VPoint> points, final Agent pedestrain) {
renderTrajectory(g, points.stream(), pedestrain); renderTrajectory(g, points.stream(), pedestrain);
} }
protected void renderTrajectory(final Graphics2D g, final Stream<VPoint> points, final Agent pedestrain) { protected void renderTrajectory(final Graphics2D g, final Stream<VPoint> points, final Agent pedestrain) {
Color color = g.getColor(); Color color = g.getColor();
Stroke stroke = g.getStroke(); Stroke stroke = g.getStroke();
if (model.isElementSelected() && model.getSelectedElement().equals(pedestrain)) { if (model.isElementSelected() && model.getSelectedElement().equals(pedestrain)) {
g.setColor(Color.MAGENTA); g.setColor(Color.MAGENTA);
g.setStroke(new BasicStroke(getLineWidth() / 2.0f)); g.setStroke(new BasicStroke(getLineWidth() / 2.0f));
} else { } else {
g.setStroke(new BasicStroke(getLineWidth() / 4.0f)); g.setStroke(new BasicStroke(getLineWidth() / 4.0f));
} }
Path2D.Double path = new Path2D.Double(); Path2D.Double path = new Path2D.Double();
path.moveTo(pedestrain.getPosition().getX(), pedestrain.getPosition().getY()); path.moveTo(pedestrain.getPosition().getX(), pedestrain.getPosition().getY());
points.forEachOrdered( points.forEachOrdered(
p -> path.lineTo(p.getX(), p.getY())); p -> path.lineTo(p.getX(), p.getY()));
g.draw(path); g.draw(path);
g.setColor(color); g.setColor(color);
// g.setStroke(stroke); // g.setStroke(stroke);
} }
private void renderDensity(final Graphics2D g) { protected void renderTriangulation(final Graphics2D g, final Collection<VTriangle> triangleList) {
CLGaussianCalculator densityCalculator = new CLGaussianCalculator(model, model.config.getDensityScale(), g.setColor(Color.GRAY);
model.config.getDensityMeasurementRadius(), g.setStroke(new BasicStroke(getGridLineWidth()));
model.config.getDensityColor(), true, true); triangleList.stream().forEach(triangle -> g.draw(triangle));
}
private void renderDensity(final Graphics2D g) {
CLGaussianCalculator densityCalculator = new CLGaussianCalculator(model, model.config.getDensityScale(),
model.config.getDensityMeasurementRadius(),
model.config.getDensityColor(), true, true);
/* /*
* if (obstacleDensity == null || !model.config.getDensityColor().equals(lastDensityColor) * if (obstacleDensity == null || !model.config.getDensityColor().equals(lastDensityColor)
* || model.getTopographyId() != topographyId) { * || model.getTopographyId() != topographyId) {
...@@ -152,44 +160,49 @@ public abstract class SimulationRenderer extends DefaultRenderer { ...@@ -152,44 +160,49 @@ public abstract class SimulationRenderer extends DefaultRenderer {
* model.config.getPedestrianTorso()); * model.config.getPedestrianTorso());
*/ */
BufferedImage densityImage = densityCalculator.getDensityImage(); BufferedImage densityImage = densityCalculator.getDensityImage();
g.scale(1.0 / model.config.getDensityScale(), 1.0 / model.config.getDensityScale()); g.scale(1.0 / model.config.getDensityScale(), 1.0 / model.config.getDensityScale());
g.drawImage(densityImage, 0, 0, null); g.drawImage(densityImage, 0, 0, null);
// g.drawImage(pedestrianDensity, 0, 0, null); // g.drawImage(pedestrianDensity, 0, 0, null);
g.scale(model.config.getDensityScale(), model.config.getDensityScale()); g.scale(model.config.getDensityScale(), model.config.getDensityScale());
} densityCalculator.destroy();
}
private void renderPotentialField(final Graphics2D g, final int width, final int height) { private void renderPotentialField(final Graphics2D g, final int width, final int height) {
/* /*
* This calculation we need since the viewport.y = 0 if the user scrolls to the bottom * This calculation we need since the viewport.y = 0 if the user scrolls to the bottom
*/ */
Rectangle2D.Double viewportBound = model.getViewportBound(); Rectangle2D.Double viewportBound = model.getViewportBound();
double dy = model.getTopographyBound().getHeight() - viewportBound.getHeight(); double dy = model.getTopographyBound().getHeight() - viewportBound.getHeight();
int startX = (int) (viewportBound.getX() * model.getScaleFactor()); int startX = (int) (viewportBound.getX() * model.getScaleFactor());
int startY = (int) (Math.max((dy - viewportBound.getY()), 0) * model.getScaleFactor()); int startY = (int) (Math.max((dy - viewportBound.getY()), 0) * model.getScaleFactor());
potentialFieldImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); potentialFieldImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < potentialFieldImage.getWidth(); x++) { for (int x = 0; x < potentialFieldImage.getWidth(); x++) {
for (int y = 0; y < potentialFieldImage.getHeight(); y++) { for (int y = 0; y < potentialFieldImage.getHeight(); y++) {
Color c; Color c;
double potential = model.getPotential(x + startX, y + startY); double potential = model.getPotential(x + startX, y + startY);
if (potential >= MAX_POTENTIAL) { if (potential >= MAX_POTENTIAL) {
c = model.config.getObstacleColor(); c = model.config.getObstacleColor();
} else if (potential % CONTOUR_STEP <= CONTOUR_THINKNESS) { } else if (potential % CONTOUR_STEP <= CONTOUR_THINKNESS) {
c = Color.BLACK; c = Color.BLACK;
} else { } else {
c = colorHelper.numberToColor(potential % 100); c = colorHelper.numberToColor(potential % 100);
} }
potentialFieldImage.setRGB(x, y, c.getRGB()); potentialFieldImage.setRGB(x, y, c.getRGB());
} }
} }
g.drawImage(potentialFieldImage, 0, 0, null); g.drawImage(potentialFieldImage, 0, 0, null);
} }
protected abstract void renderSimulationContent(final Graphics2D g); protected abstract void renderSimulationContent(final Graphics2D g);
}
private float getGridLineWidth() {
return (float) (0.5 / model.getScaleFactor());
}
}
\ No newline at end of file
...@@ -8,16 +8,22 @@ import org.vadere.util.opencl.CLConvolution; ...@@ -8,16 +8,22 @@ import org.vadere.util.opencl.CLConvolution;
class CLGaussianFilter extends GaussianFilter { class CLGaussianFilter extends GaussianFilter {
private final CLConvolution convolution; private final CLConvolution convolution;
CLGaussianFilter(final Rectangle2D scenarioBounds, final double scale, final BiFunction<Integer, Integer, Float> f, CLGaussianFilter(final Rectangle2D scenarioBounds, final double scale, final BiFunction<Integer, Integer, Float> f,
final boolean normalize) throws IOException { final boolean normalize) throws IOException {
super(scenarioBounds, scale, f, normalize); super(scenarioBounds, scale, f, normalize);
this.convolution = new CLConvolution(); this.convolution = new CLConvolution(matrixWidth, matrixHeight, kernelWidth, kernel);
} this.convolution.init();
}
@Override @Override
public void filterImage() { public void filterImage() {
outputMatrix = this.convolution.convolveSeparate(inputMatrix, matrixWidth, matrixHeight, kernel, kernelWidth); outputMatrix = this.convolution.convolve(inputMatrix);
} }
@Override
public void destroy() {
this.convolution.clearCL();
}
} }
...@@ -10,118 +10,119 @@ import java.util.stream.IntStream; ...@@ -10,118 +10,119 @@ import java.util.stream.IntStream;
abstract class GaussianFilter implements IGaussianFilter { abstract class GaussianFilter implements IGaussianFilter {
/** /**
* the scale of the images respect to the scenario width and heigt and based on the * the scale of the images respect to the scenario width and heigt and based on the
* gridresolution of the potential field grid. * gridresolution of the potential field grid.
*/ */
protected final double scale; protected final double scale;
/** the width of the scenario. */ /** the width of the scenario. */
protected final int scenarioWidth; protected final int scenarioWidth;
/** the height of the scenario. */ /** the height of the scenario. */
protected final int scenarioHeight; protected final int scenarioHeight;
protected float[] inputMatrix; protected float[] inputMatrix;
protected float[] outputMatrix; protected float[] outputMatrix;