From 62e64b95b2b9167127acd865244eaed2d52fbee8 Mon Sep 17 00:00:00 2001 From: lehtonen Date: Thu, 2 Dec 2010 19:56:24 +0000 Subject: [PATCH] Discovered and fixed some of the most obvious and major/minor memory allocation goofs in the scene graph rendering code. The next major bottleneck in the scene graph with regard to huge memory allocation is the problem that all events are currently propagated recursively throughout the whole scene graph by G2DParentNode. J-P and I considered adding a separate listener registration mechanism as in DOM. While at it, we must specify better how the scene graph event handling is performed and write it down. git-svn-id: https://www.simantics.org/svn/simantics/sysdyn/trunk@18922 ac1ea38d-2e2b-0410-8846-a27921b304fc --- .../sysdyn/ui/elements2/HoverTextNode.java | 33 ++++++++-------- .../connections/SysdynConnectionClass.java | 39 ++++++++++++++----- 2 files changed, 47 insertions(+), 25 deletions(-) diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements2/HoverTextNode.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements2/HoverTextNode.java index 35b67733..d68d63c2 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements2/HoverTextNode.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements2/HoverTextNode.java @@ -14,8 +14,6 @@ package org.simantics.sysdyn.ui.elements2; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics2D; -import java.awt.font.FontRenderContext; -import java.awt.geom.NoninvertibleTransformException; import java.awt.geom.Rectangle2D; import org.simantics.diagram.elements.TextNode; @@ -27,38 +25,41 @@ public class HoverTextNode extends TextNode implements ISelectionPainterNode { private static final long serialVersionUID = 3539499125943249895L; + private static transient ThreadLocal tempBounds = new ThreadLocal() { + @Override + protected Rectangle2D initialValue() { + return new Rectangle2D.Double(); + } + }; @Override public void render(Graphics2D g) { - + if (text == null || font == null || color == null) + return; + g.transform(transform); - if(horizontalAlignment == Alignment.CENTER.ordinal()) { - FontRenderContext frc = g.getFontRenderContext(); - Rectangle2D stringBounds = font.getStringBounds(getText(), frc); + + if (horizontalAlignment == Alignment.CENTER.ordinal()) { + // FIXME: Font.getStringBounds is expensive. Optimize so that it is only executed when the text changes. + Rectangle2D stringBounds = font.getStringBounds(text, g.getFontRenderContext()); g.translate(- stringBounds.getWidth() / 2 * scale, 0); } - Rectangle2D r = getBoundsInLocal(); - + boolean selected = NodeUtil.isSelected(this, 1); if (!selected && hover){ - BasicStroke oldStroke = (BasicStroke)g.getStroke(); Color oldColor = g.getColor(); g.setColor(Color.LIGHT_GRAY); g.setStroke(new BasicStroke((float)(2.0f * scale))); g.translate(x, y); + Rectangle2D r = expandBounds( alignBounds( getTightUnalignedBoundsInLocal( tempBounds.get() ) ) ); g.draw(r); g.translate(-x, -y); g.setColor(oldColor); g.setStroke(oldStroke); } - try { - g.transform(transform.createInverse()); - } catch (NoninvertibleTransformException e) { - e.printStackTrace(); - } - super.render(g); - + super.render(g, false); } + } diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements2/connections/SysdynConnectionClass.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements2/connections/SysdynConnectionClass.java index 3f95c68a..a98c5c04 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements2/connections/SysdynConnectionClass.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements2/connections/SysdynConnectionClass.java @@ -80,13 +80,18 @@ public class SysdynConnectionClass { SimpleElementLayers.INSTANCE ).setId(SysdynConnectionClass.class.getSimpleName()); - private static final ThreadLocal> perThreadElementList = new ThreadLocal>() { + private static class ThreadLocalList extends ThreadLocal> { @Override protected java.util.List initialValue() { return new ArrayList(); } }; + private static final ThreadLocal> perThreadSceneGraphList = new ThreadLocalList(); + private static final ThreadLocal> perThreadBoundsList = new ThreadLocalList(); + private static final ThreadLocal> perThreadShapeList = new ThreadLocalList(); + private static final ThreadLocal> perThreadPickList = new ThreadLocalList(); + static class ConnectionHandlerImpl implements ConnectionHandler { public static final ConnectionHandlerImpl INSTANCE = new ConnectionHandlerImpl(); @@ -172,7 +177,7 @@ public class SysdynConnectionClass { return; // Painting is single-threaded, it is OK to use a single thread-local collection here. - List children = perThreadElementList.get(); + List children = perThreadSceneGraphList.get(); children.clear(); ce.getSegments(children); ce.getBranchPoints(children); @@ -207,7 +212,7 @@ public class SysdynConnectionClass { Composite composite = child.getHint(ElementHints.KEY_COMPOSITE); - holder.setTransform(at2); + holder.setTransform((AffineTransform) at2.clone()); holder.setComposite(composite); holder.setVisible(true); @@ -256,7 +261,9 @@ public class SysdynConnectionClass { if (ce == null) return size; - Collection parts = ce.getSegments(null); + Collection parts = perThreadBoundsList.get(); + parts.clear(); + parts = ce.getSegments(parts); if (parts.isEmpty()) return size; parts = ce.getBranchPoints(parts); @@ -277,8 +284,11 @@ public class SysdynConnectionClass { //System.out.println("InternalSize Combined BOUNDS: " + temp); } size.setRect(temp); + + // Don't leave dangling references behind. + parts.clear(); + return size; - } private Shape getSelectionShape(IElement forPart) { @@ -302,7 +312,9 @@ public class SysdynConnectionClass { if (ce == null) return new Rectangle2D.Double(); - Collection parts = ce.getSegments(null); + Collection parts = perThreadShapeList.get(); + parts.clear(); + parts = ce.getSegments(parts); if (parts.isEmpty()) return new Rectangle2D.Double(); parts = ce.getBranchPoints(parts); @@ -350,6 +362,9 @@ public class SysdynConnectionClass { area.add(a); } + // Don't leave dangling references behind. + parts.clear(); + //System.out.println(" connection area outline: " + area); //System.out.println(" connection area outline bounds: " + area.getBounds2D()); return area; @@ -369,7 +384,9 @@ public class SysdynConnectionClass { return false; // Primarily pick branch points and then edges. - Collection parts = ce.getBranchPoints(null); + Collection parts = perThreadPickList.get(); + parts.clear(); + parts = ce.getBranchPoints(parts); parts = ce.getSegments(parts); if (parts.isEmpty()) return false; @@ -384,6 +401,8 @@ public class SysdynConnectionClass { } } + parts.clear(); + return false; } @@ -398,7 +417,7 @@ public class SysdynConnectionClass { return 0; // Primarily pick branch points and then edges. - List parts = perThreadElementList.get(); + List parts = perThreadPickList.get(); parts.clear(); ce.getSegments(parts); @@ -485,8 +504,10 @@ public class SysdynConnectionClass { } } + parts.clear(); + // System.out.println("pick result size = " + result.size()); - + return result.size() - oldResultSize; } } -- 2.47.1