diff -r a2b08e30a638 modules/graphics/src/main/java/com/sun/javafx/sg/prism/CacheFilter.java
--- a/modules/graphics/src/main/java/com/sun/javafx/sg/prism/CacheFilter.java	Tue Nov 19 11:42:28 2013 +0200
+++ b/modules/graphics/src/main/java/com/sun/javafx/sg/prism/CacheFilter.java	Tue Nov 19 14:38:42 2013 +0100
@@ -26,6 +26,8 @@
 package com.sun.javafx.sg.prism;
 
 import com.sun.javafx.logging.PulseLogger;
+import com.sun.prism.ResourceFactory;
+import com.sun.prism.impl.packrect.RectanglePacker;
 import javafx.scene.CacheHint;
 import java.util.List;
 import com.sun.javafx.geom.BaseBounds;
@@ -557,17 +559,17 @@
             }
 
             cacheBounds = impl_getCacheBounds(cacheBounds, cachedXform);
-            cachedImageData = impl_createImageData(fctx, cacheBounds);
+            cachedImageData = impl_createImageData(g.getResourceFactory(), fctx, cacheBounds);
             impl_renderNodeToCache(cachedImageData, cacheBounds, cachedXform, null);
 
             // cachedBounds includes effects, and is in *scene* coords
-            Rectangle cachedBounds = cachedImageData.getUntransformedBounds();
+            //Rectangle cachedBounds = cachedImageData.getUntransformedBounds();
 
             // Save out the (un-transformed) x & y coordinates.  This accounts
             // for effects and other reasons the untranslated location may not
             // be 0,0.
-            cachedX = cachedBounds.x;
-            cachedY = cachedBounds.y;
+            cachedX = cacheBounds.x;
+            cachedY = cacheBounds.y;
 
         } else {
             if (scrollCacheState == ScrollCacheState.ENABLED &&
@@ -605,21 +607,38 @@
         }
     }
 
+    private static Object cacheLock = new Object();
+    private static Filterable cache;
+    private static RectanglePacker packer;
     /**
      * Create the ImageData for the cached bitmap, with the specified bounds.
      */
-    ImageData impl_createImageData(FilterContext fctx, Rectangle bounds) {
-        Filterable ret;
-        try {
-            ret = Effect.getCompatibleImage(fctx,
-                    bounds.width, bounds.height);
-            Texture cachedTex = ((PrDrawable) ret).getTextureObject();
-            cachedTex.contentsUseful();
-        } catch (Throwable e) {
-            ret = null;
+    ImageData impl_createImageData(ResourceFactory factory, FilterContext fctx, Rectangle bounds) {
+        synchronized (cacheLock) {
+            try {
+                if (cache == null) {
+                    cache = Effect.getCompatibleImage(fctx, factory.getMaximumTextureSize(), factory.getMaximumTextureSize());
+                }
+                Texture cachedTex = ((PrDrawable) cache).getTextureObject();
+                if (!cachedTex.isLocked()) {
+                    cachedTex.lock();
+                }
+                cachedTex.contentsUseful();
+                if (packer == null) {
+                    packer = new RectanglePacker(cachedTex, cachedTex.getPhysicalWidth(), cachedTex.getPhysicalHeight());
+                }
+                final Rectangle finalBounds = new Rectangle(bounds);
+                if (packer.add(finalBounds)) {
+                    System.out.println("Caching node: " + node  + ", cache: " + cache + ", tex: " + cachedTex + ", bounds: " + finalBounds);
+                    return new ImageData(fctx, cache, finalBounds);
+                }
+                System.out.println("Caching node: " + node  + " failed");
+            } catch (Throwable e) {
+                //System.out.println("Caching node: " + node  + " failed with exc: ");
+                e.printStackTrace(System.out);
+            }
         }
-
-        return new ImageData(fctx, ret, bounds);
+        return new ImageData(fctx, null, bounds);
     }
 
     /**
@@ -638,7 +657,8 @@
         if (image != null) {
             Graphics g = image.createGraphics();
             TEMP_CACHEFILTER_TRANSFORM.setToIdentity();
-            TEMP_CACHEFILTER_TRANSFORM.translate(-cacheBounds.x, -cacheBounds.y);
+            TEMP_CACHEFILTER_TRANSFORM.translate(-cacheBounds.x + cacheData.getUntransformedBounds().x,
+                    -cacheBounds.y + cacheData.getUntransformedBounds().y);
             if (xform != null) {
                 TEMP_CACHEFILTER_TRANSFORM.concatenate(xform);
             }
@@ -689,9 +709,10 @@
                        mxt, myt);
         g.translate((float)cachedX, (float)cachedY);
         Texture cachedTex = ((PrDrawable)implImage).getTextureObject();
-        Rectangle cachedBounds = cachedImageData.getUntransformedBounds();
-        g.drawTexture(cachedTex, 0, 0,
-                      cachedBounds.width, cachedBounds.height);
+        final Rectangle cb = cachedImageData.getUntransformedBounds();
+        g.drawTexture(cachedTex,
+                0, 0, cb.width, cb.height,
+                cb.x, cb.y, cb.x + cb.width, cb.y + cb.height);
         // FYI: transform state is restored by the NGNode.render() method
     }
