changeset 4925:e0f3abebc024 8.0-b106

Automated merge with ssh://jfxsrc.us.oracle.com//javafx/8.0/MASTER/jfx/rt
author jgodinez
date Tue, 03 Sep 2013 09:40:03 -0700
parents ec82a5c0079b ec2f564fb7a1
children 361d97db0d1c e94c28bc5396 0a2518e15882
files build.gradle modules/graphics/src/main/java/com/sun/javafx/WeakReferenceMap.java modules/graphics/src/test/java/com/sun/javafx/WeakReferenceMapTest.java
diffstat 100 files changed, 3831 insertions(+), 1592 deletions(-) [+]
line wrap: on
line diff
--- a/apps/performance/GraphicsPerformance/src/main/java/nodecount/BenchBase.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/apps/performance/GraphicsPerformance/src/main/java/nodecount/BenchBase.java	Tue Sep 03 09:40:03 2013 -0700
@@ -35,6 +35,7 @@
 import javafx.animation.Animation;
 import javafx.animation.AnimationTimer;
 import javafx.application.Application;
+import javafx.application.Platform;
 import javafx.event.ActionEvent;
 import javafx.event.EventHandler;
 import javafx.scene.Group;
@@ -51,8 +52,7 @@
 
     @Override
     public void start(Stage stage) throws Exception {
-
-        Scene scene = new Scene(new Group(), 640, 480);
+        Scene scene = new Scene(new Group(), 1024, 768);
         stage.setScene(scene);
         stage.show();
 
@@ -118,6 +118,7 @@
     private void runTest(Scene scene, BenchTest[] tests, int index) {
         if (index >= tests.length) {
             printResults(tests);
+            Platform.exit();
             return; // we're done.
         }
 
@@ -135,6 +136,7 @@
                 runTest(scene, tests, index+1);
             }
         });
+        System.out.println("Starting test: " + currentTest);
     }
 
     /**
--- a/apps/performance/GraphicsPerformance/src/main/java/nodecount/BenchTest.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/apps/performance/GraphicsPerformance/src/main/java/nodecount/BenchTest.java	Tue Sep 03 09:40:03 2013 -0700
@@ -114,6 +114,6 @@
     public void tearDown() { }
 
     @Override public String toString() {
-        return getClass().getSimpleName() + " " + rows + "x" + cols + ": " + maxFPS;
+        return getClass().getSimpleName() + " " + rows + "x" + cols;
     }
 }
--- a/apps/performance/GraphicsPerformance/src/main/java/scrolling/ScrollingBenchBase.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/apps/performance/GraphicsPerformance/src/main/java/scrolling/ScrollingBenchBase.java	Tue Sep 03 09:40:03 2013 -0700
@@ -56,9 +56,9 @@
         for (int i=0; i<tests.length; i+=3) {
             int rows = sizes[sizeIndex][0];
             int cols = sizes[sizeIndex][1];
-            tests[i] = new TranslatingGridTest(this, rows, cols);
-            tests[i+1] = new ScrollPaneGridTest(this, rows, cols);
-            tests[i+2] = new PixelAlignedTranslatingGridTest(this, rows, cols);
+            tests[i] = new TranslatingGridTest(this, rows, cols); // Causing all rects to be drawn? Grows with each iteration!
+            tests[i+1] = new ScrollPaneGridTest(this, rows, cols); // Very few rects drawn
+            tests[i+2] = new PixelAlignedTranslatingGridTest(this, rows, cols); // causes all rects to be drawn at first and then only very few thereafter
             sizeIndex++;
         }
         return tests;
--- a/apps/samples/Ensemble8/src/app/java/ensemble/EnsembleApp.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/apps/samples/Ensemble8/src/app/java/ensemble/EnsembleApp.java	Tue Sep 03 09:40:03 2013 -0700
@@ -67,7 +67,7 @@
     private static final String OS_NAME = System.getProperty("ensemble.os.name", System.getProperty("os.name"));
     private static final String OS_ARCH = System.getProperty("ensemble.os.arch", System.getProperty("os.arch"));
     public static final boolean IS_IPHONE = false;
-    public static final boolean IS_IOS = "isOS".equals(OS_NAME);
+    public static final boolean IS_IOS = "iOS".equals(OS_NAME);
     public static final boolean IS_EMBEDDED = "arm".equals(OS_ARCH) && !IS_IOS;
     public static final boolean IS_DESKTOP = !IS_EMBEDDED && !IS_IOS;
     public static final boolean IS_MAC = OS_NAME.startsWith("Mac");
@@ -309,7 +309,7 @@
     @Override public void start(final Stage stage) throws Exception {
         // CREATE SCENE
         scene = new Scene(root, 1024, 768, Color.BLACK);
-        if (IS_EMBEDDED || IS_IOS) {
+        if (IS_EMBEDDED) {
             new ScrollEventSynthesizer(scene);
         }
         setStylesheets(SELECT_IOS_THEME);
--- a/apps/samples/Ensemble8/src/app/java/ensemble/HomePage.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/apps/samples/Ensemble8/src/app/java/ensemble/HomePage.java	Tue Sep 03 09:40:03 2013 -0700
@@ -32,14 +32,6 @@
 
 package ensemble;
 
-import ensemble.generated.Samples;
-import java.lang.ref.Reference;
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.WeakHashMap;
 import javafx.beans.property.ReadOnlyStringProperty;
 import javafx.beans.property.ReadOnlyStringWrapper;
 import javafx.beans.value.ChangeListener;
@@ -48,8 +40,17 @@
 import javafx.event.EventHandler;
 import javafx.geometry.Pos;
 import javafx.scene.Node;
-import javafx.scene.control.*;
-import javafx.scene.effect.*;
+import javafx.scene.control.Button;
+import javafx.scene.control.ContentDisplay;
+import javafx.scene.control.ListCell;
+import javafx.scene.control.ListView;
+import javafx.scene.control.Pagination;
+import javafx.scene.control.Skin;
+import javafx.scene.effect.BlendBuilder;
+import javafx.scene.effect.BlurType;
+import javafx.scene.effect.DropShadowBuilder;
+import javafx.scene.effect.Effect;
+import javafx.scene.effect.InnerShadowBuilder;
 import javafx.scene.image.Image;
 import javafx.scene.image.ImageView;
 import javafx.scene.layout.HBox;
@@ -57,7 +58,15 @@
 import javafx.scene.paint.Color;
 import javafx.scene.text.Text;
 import javafx.util.Callback;
-import static ensemble.EnsembleApp.*;
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.WeakHashMap;
+import ensemble.generated.Samples;
+import static ensemble.EnsembleApp.SHOW_HIGHLIGHTS;
 
 /**
  * The home page for ensemble.
@@ -97,7 +106,7 @@
         setId("HomePage");
         // don't use any of the standard ListView CSS
         //   getStyleClass().clear();
-       
+
         // listen for when the list views width changes and recalculate number of columns
         widthProperty().addListener(this);
         // set our custom cell factory
@@ -137,7 +146,7 @@
     @Override public ListCell<HomePageRow> call(ListView<HomePageRow> homePageRowListView) {
         return new HomeListCell();
     }
-    
+
     // Called to rebuild the list's items based on the current number of columns
     private void rebuild() {
         // build new list of titles and samples
@@ -307,62 +316,6 @@
         }
     }
 
-
-//    private class HomeListCell extends ListCell<HomePageRow> implements ChangeListener<HomePageRow>, Callback<Integer,Node> {
-//        private HomeListCell() {
-//            super();
-//            // don't use any of the standard CSS
-//            getStyleClass().setAll("home-page-cell");
-//            itemProperty().addListener(this);
-////            setSkin(new Label("DUDE"));
-//        }
-//
-//        @Override protected void updateItem(HomePageRow item, boolean empty) {
-//            super.updateItem(item, empty);
-//        }
-//
-//        @Override public void changed(ObservableValue<? extends HomePageRow> observableValue, HomePageRow oldRow, HomePageRow newRow) {
-//            setText(null);
-//            if (newRow == null) {
-//                setGraphic(null);
-//            } else {
-//                switch(newRow.rowType) {
-//                    case Highlights:
-////                        Pagination pagination = new Pagination(Samples.HIGHLIGHTS.length);
-////                        pagination.setMaxWidth(USE_PREF_SIZE);
-////                        pagination.setPageFactory(this);
-////                        setGraphic(pagination);
-//                        setGraphic(Samples.HIGHLIGHTS[0].getLargePreview());
-//                        setAlignment(Pos.CENTER);
-//                        break;
-//                    case Title:
-//                        SectionRibbon sectionRibbon = new SectionRibbon(newRow.title+"  public void changed(Obs");
-//                        setAlignment(Pos.CENTER_LEFT);
-//                        setGraphic(sectionRibbon);
-//                        break;
-//                    case Samples:
-//                        setAlignment(Pos.CENTER);
-//                        HBox hbox = new HBox(ITEM_GAP);
-//                        setGraphic(hbox);
-//                        hbox.setMaxWidth(USE_PREF_SIZE);
-//                        hbox.setAlignment(Pos.CENTER);
-//                        for (SampleInfo sample:newRow.samples) {
-//                            Label sampleLabel = new Label(sample.name);
-//                            sampleLabel.getStyleClass().add("sample-label");
-//                            sampleLabel.setGraphic(sample.getMediumPreview());
-//                            sampleLabel.setContentDisplay(ContentDisplay.TOP);
-//                            hbox.getChildren().add(sampleLabel);
-//                        }
-//                        break;
-//                }
-//            }
-//        }
-//
-//        @Override public Node call(Integer integer) {
-//            return Samples.HIGHLIGHTS[integer].getLargePreview();
-//        }
-//    }
-
     public static class HomePageRow {
         public final RowType rowType;
         public final String title;
--- a/apps/samples/Ensemble8/src/app/java/ensemble/PageBrowser.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/apps/samples/Ensemble8/src/app/java/ensemble/PageBrowser.java	Tue Sep 03 09:40:03 2013 -0700
@@ -31,9 +31,6 @@
  */
 package ensemble;
 
-import ensemble.generated.Samples;
-import ensemble.samplepage.SamplePage;
-import java.util.LinkedList;
 import javafx.beans.property.BooleanProperty;
 import javafx.beans.property.ReadOnlyBooleanProperty;
 import javafx.beans.property.ReadOnlyStringProperty;
@@ -42,6 +39,9 @@
 import javafx.beans.property.StringProperty;
 import javafx.scene.Node;
 import javafx.scene.layout.Region;
+import java.util.LinkedList;
+import ensemble.generated.Samples;
+import ensemble.samplepage.SamplePage;
 
 /**
  * Sample page navigation with history.
@@ -152,7 +152,7 @@
                 throw new UnsupportedOperationException("Unknown sample url ["+url+"]");
             }
         } else {
-            throw new UnsupportedOperationException("Unknown ensmeble page url ["+url+"]");
+            throw new UnsupportedOperationException("Unknown ensemble page url ["+url+"]");
         }
         // update properties
         atHome.set(url.equals(HOME_URL));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/toys/FX8-3DFeatures/src/fx83dfeatures/SimpleMeshTexCoordTest.java	Tue Sep 03 09:40:03 2013 -0700
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package fx83dfeatures;
+
+import javafx.application.Application;
+import javafx.scene.*;
+import javafx.scene.image.Image;
+import javafx.scene.paint.Color;
+import javafx.scene.paint.PhongMaterial;
+import javafx.scene.shape.*;
+import javafx.stage.Stage;
+
+public class SimpleMeshTexCoordTest extends Application {
+
+    Group root;
+    PointLight pointLight;
+    MeshView meshView;
+    TriangleMesh triMesh;
+    PhongMaterial material;
+    final Image diffuseMap = new Image("resources/cup_diffuseMap_1024.png");
+    
+    static TriangleMesh buildTriangleMesh() {
+
+        // Create points
+        float points[] = {
+            0.0f, 0.0f, 0.0f,
+            400.0f, 0.0f, 0.0f,
+            0.0f, 400.0f, 0.0f,
+            400.0f, 400.0f, 0.0f};
+
+        // Create texCoords
+        float texCoords[] = {
+            0.0f, 0.0f,
+            1.0f, 0.0f,
+            0.0f, 1.0f,
+            1.0f, 1.0f
+        };
+
+        // Create faces
+        // Interleaving 3 point indices and 3 texCoord indices per triangle
+        int faces[] = {
+            // Triangle #1
+            0, 0, 2, 2, 3, 3,
+            // Triangle #2
+            3, 3, 1, 1, 0, 0
+        };
+
+        TriangleMesh triangleMesh = new TriangleMesh();
+        triangleMesh.getPoints().setAll(points);
+        triangleMesh.getTexCoords().setAll(texCoords);
+        triangleMesh.getFaces().setAll(faces);
+
+        return triangleMesh;
+    }
+
+    private Group buildScene() {
+        triMesh = buildTriangleMesh();
+
+        material = new PhongMaterial();
+        material.setDiffuseMap(diffuseMap);
+        material.setSpecularColor(Color.rgb(30, 30, 30));
+        meshView = new MeshView(triMesh);
+        meshView.setTranslateX(200);
+        meshView.setTranslateY(200);
+        meshView.setTranslateZ(20);
+        meshView.setMaterial(material);
+        meshView.setDrawMode(DrawMode.FILL);
+        meshView.setCullFace(CullFace.BACK);
+
+        pointLight = new PointLight(Color.ANTIQUEWHITE);
+        pointLight.setTranslateX(150);
+        pointLight.setTranslateY(-100);
+        pointLight.setTranslateZ(-1000);
+
+        root = new Group(meshView, pointLight);
+        return root;
+    }
+
+    private PerspectiveCamera addCamera(Scene scene) {
+        PerspectiveCamera perspectiveCamera = new PerspectiveCamera();
+        scene.setCamera(perspectiveCamera);
+        return perspectiveCamera;
+    }
+
+    @Override
+    public void start(Stage primaryStage) {
+        Scene scene = new Scene(buildScene(), 800, 800, true);
+        scene.setFill(Color.GRAY);
+        addCamera(scene);
+        primaryStage.setTitle("SimpleMeshTexCoordTest");
+        primaryStage.setScene(scene);
+        primaryStage.show();
+    }
+
+    public static void main(String[] args) {
+        launch(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/toys/Hello/src/main/java/hello/HelloOverdraw.java	Tue Sep 03 09:40:03 2013 -0700
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package hello;
+
+import javafx.animation.RotateTransition;
+import javafx.application.Application;
+import javafx.event.EventHandler;
+import javafx.scene.Group;
+import javafx.scene.PerspectiveCamera;
+import javafx.scene.Scene;
+import javafx.scene.input.KeyEvent;
+import javafx.scene.input.MouseEvent;
+import javafx.scene.paint.Color;
+import javafx.scene.shape.Rectangle;
+import javafx.scene.transform.Rotate;
+import javafx.stage.Stage;
+import javafx.util.Duration;
+
+/**
+ * Has some rectangles with the intention of showing dirty regions and overdraw. Set these:
+ * -Djavafx.pulseLogger=true
+ * -Dprism.showoverdraw=true
+ * -Dprism.printrendergraph=true
+ * -Djavafx.pulseLogger.threshold=0
+ */
+public class HelloOverdraw extends Application {
+    @Override public void start(Stage stage) {
+        stage.setTitle("Hello Overdraw");
+
+        Rectangle clipped = createRectangle("clipped", 400, 50, 100, 100, Color.LIGHTGRAY);
+        Rectangle clip = new Rectangle(400, 50, 50, 50);
+        clipped.setClip(clip);
+
+        final Rectangle russianDolls0 = createRectangle("russianDoll0", 300, 200, 200, 200, Color.LIGHTGRAY);
+        final Rectangle russianDolls1 = createRectangle("russianDoll1", 310, 210, 180, 180, Color.LIGHTGRAY.darker());
+        final Rectangle russianDolls2 = createRectangle("russianDoll2", 320, 220, 160, 160, Color.LIGHTGRAY.darker().darker());
+        final Rectangle russianDolls3 = createRectangle("russianDoll3", 330, 230, 140, 140, Color.LIGHTGRAY.darker().darker().darker());
+        final Rectangle russianDolls4 = createRectangle("russianDoll4", 340, 240, 120, 120, Color.LIGHTGRAY.darker().darker().darker().darker());
+        final Rectangle russianDolls5 = createRectangle("russianDoll5", 350, 250, 100, 100, Color.LIGHTGRAY.darker().darker().darker().darker().darker());
+        final Rectangle russianDolls6 = createRectangle("russianDoll6", 360, 260, 80, 80, Color.LIGHTGRAY.darker().darker().darker().darker().darker().darker());
+        final Rectangle russianDolls7 = createRectangle("russianDoll7", 370, 270, 60, 60, Color.LIGHTGRAY.darker().darker().darker().darker().darker().darker().darker());
+
+        Group root = new Group(
+                clipped,
+                russianDolls0,
+                russianDolls1,
+                russianDolls2,
+                russianDolls3,
+                russianDolls4,
+                russianDolls5,
+                russianDolls6,
+                russianDolls7,
+                createRectangle("bottom", 50, 50, 100, 100, Color.LIGHTGRAY),
+                createRectangle("top", 100, 100, 100, 100, Color.LIGHTGRAY),
+                createRectangle("loner", 100, 300, 100, 100, Color.LIGHTGRAY));
+        Scene scene = new Scene(root, 600, 450);
+        scene.setCamera(new PerspectiveCamera());
+        stage.setScene(scene);
+        stage.show();
+
+        scene.setOnKeyReleased(new EventHandler<KeyEvent>() {
+            @Override
+            public void handle(KeyEvent event) {
+                switch (event.getCode()) {
+                    case DIGIT0: toggle(russianDolls0); break;
+                    case DIGIT1: toggle(russianDolls1); break;
+                    case DIGIT2: toggle(russianDolls2); break;
+                    case DIGIT3: toggle(russianDolls3); break;
+                    case DIGIT4: toggle(russianDolls4); break;
+                    case DIGIT5: toggle(russianDolls5); break;
+                    case DIGIT6: toggle(russianDolls6); break;
+                    case DIGIT7: toggle(russianDolls7); break;
+                }
+            }
+        });
+    }
+
+    private void toggle(Rectangle r) {
+        if (r.getArcHeight() == 0) {
+            round(r);
+        } else {
+            squareUp(r);
+        }
+    }
+
+    private void rotate(Rectangle r) {
+        RotateTransition tx = new RotateTransition(Duration.seconds(10), r);
+        tx.setFromAngle(0);
+        tx.setToAngle(360);
+        tx.setAxis(Rotate.Z_AXIS);
+        tx.play();
+    }
+
+    private void rotate3D(Rectangle r) {
+        RotateTransition tx = new RotateTransition(Duration.seconds(10), r);
+        tx.setFromAngle(0);
+        tx.setToAngle(360);
+        tx.setAxis(Rotate.Y_AXIS);
+        tx.play();
+    }
+
+    private void squareUp(Rectangle r) {
+        r.setArcHeight(0);
+        r.setArcWidth(0);
+    }
+
+    private void round(Rectangle r) {
+        r.setArcHeight(20);
+        r.setArcWidth(20);
+    }
+
+    private Rectangle createRectangle(String id, int x, int y, int w, int h, Color c) {
+        final Rectangle r = new Rectangle(x, y, w, h);
+        r.setId(id);
+        r.setArcHeight(20);
+        r.setArcWidth(20);
+        r.setFill(c);
+        r.setOnMouseEntered(new EventHandler<MouseEvent>() {
+            @Override
+            public void handle(MouseEvent event) {
+                squareUp(r);
+            }
+        });
+        r.setOnMouseExited(new EventHandler<MouseEvent>() {
+            @Override
+            public void handle(MouseEvent event) {
+                round(r);
+            }
+        });
+        r.setOnMouseClicked(new EventHandler<MouseEvent>() {
+            @Override
+            public void handle(MouseEvent event) {
+                if (event.isMetaDown()) {
+                    rotate3D(r);
+                } else {
+                    rotate(r);
+                }
+            }
+        });
+        return r;
+    }
+
+    /**
+     * @param args the command line arguments
+     */
+    public static void main(String[] args) {
+        Application.launch(args);
+    }
+}
--- a/apps/toys/Hello/src/main/java/hello/HelloRectangle.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/apps/toys/Hello/src/main/java/hello/HelloRectangle.java	Tue Sep 03 09:40:03 2013 -0700
@@ -28,12 +28,7 @@
 import javafx.application.Application;
 import javafx.scene.Group;
 import javafx.scene.Scene;
-import javafx.scene.control.Slider;
-import javafx.scene.effect.BlendMode;
-import javafx.scene.layout.VBox;
 import javafx.scene.paint.Color;
-import javafx.scene.shape.Circle;
-import javafx.scene.shape.Ellipse;
 import javafx.scene.shape.Rectangle;
 import javafx.stage.Stage;
 
@@ -46,47 +41,14 @@
         Group root = new Group();
         Scene scene = new Scene(root, 600, 450);
 
-        Slider aw = new Slider(-300, 300, 0);
-        Slider ah = new Slider(-300, 300, 0);
-
         Rectangle rect = new Rectangle();
         rect.setX(25);
         rect.setY(40);
         rect.setWidth(300);
         rect.setHeight(300);
         rect.setFill(Color.RED);
-        rect.arcWidthProperty().bind(aw.valueProperty());
-        rect.arcHeightProperty().bind(ah.valueProperty());
 
-        Circle circle = new Circle();
-        circle.setCenterX(450);
-        circle.setCenterY(200);
-        circle.setRadius(50);
-        circle.setFill(Color.RED);
-        circle.radiusProperty().bind(aw.valueProperty());
-
-        Ellipse ellipse = new Ellipse();
-        ellipse.setCenterX(450);
-        ellipse.setCenterY(375);
-        ellipse.radiusXProperty().bind(aw.valueProperty());
-        ellipse.radiusYProperty().bind(ah.valueProperty());
-        ellipse.setFill(Color.RED);
-
-        VBox box = new VBox(aw, ah);
-        box.relocate(350, 20);
-
-//        root.getChildren().addAll(rect, circle, ellipse, box);
-
-        Rectangle behind = new Rectangle(100, 100, new Color(1, 0, 0, .1));
-        Rectangle front = new Rectangle(10, 10, Color.GREEN);
-        front.setBlendMode(BlendMode.SRC_ATOP);
-
-        root.getChildren().addAll(behind, front);
-
-//        FillTransition tx = new FillTransition(Duration.seconds(3), behind, Color.RED, Color.BLUE);
-//        tx.setAutoReverse(true);
-//        tx.setCycleCount(FillTransition.INDEFINITE);
-//        tx.play();
+        root.getChildren().addAll(rect);
 
         stage.setScene(scene);
         stage.show();
--- a/build.gradle	Tue Sep 03 12:13:17 2013 -0400
+++ b/build.gradle	Tue Sep 03 09:40:03 2013 -0700
@@ -1882,16 +1882,9 @@
                 if (COMPILE_WEBKIT) {
                     from ("modules/web/build/libs/${t.name}/${library('jfxwebkit')}")
                 } else {
-                    if (t.name == "android") {
-                        //don't copy anything, use built in webkit.
+                    if (t.name != "android" && t.name != "ios") {
+                        from ("$LIBRARY_STUB/${library('jfxwebkit')}")
                     }
-                    else if (IS_MAC && COMPILE_TARGETS != "ios") from ("$LIBRARY_STUB/libjfxwebkit.dylib")
-                    else if (IS_WINDOWS) {
-                        from ("$LIBRARY_STUB/jfxwebkit.dll")
-                        from ("$LIBRARY_STUB/libxml2.dll")
-                        from ("$LIBRARY_STUB/libxslt.dll")
-                    }                    
-                    else from ("$LIBRARY_STUB/libjfxwebkit.so")
                 }
                 def libDest = targetProperties.libDest
                 into ("build/${t.name}-sdk/rt/$libDest")
@@ -2076,6 +2069,7 @@
                      "com.sun.webkit.PageCache",
                      "com.sun.webkit.PopupMenu",
                      "com.sun.webkit.SharedBuffer",
+                     "com.sun.webkit.WatchdogTimer",
                      "com.sun.webkit.WebPage",
                      "com.sun.webkit.LoadListenerClient",
                      "com.sun.webkit.event.WCFocusEvent",
--- a/buildSrc/android.gradle	Tue Sep 03 12:13:17 2013 -0400
+++ b/buildSrc/android.gradle	Tue Sep 03 09:40:03 2013 -0700
@@ -342,7 +342,7 @@
 javafx.platform=android
 android.glass.platform=Lens
 android.glass.lens=eglfb
-android.egl.depthSize=16
+android.prism.glDepthSize=16
 android.prism.lcdtext=false
 android.embedded=eglfb
 android.prism.allowhidpi=false
@@ -451,7 +451,8 @@
     file("modules/graphics/src/main/native-glass/lens/wm"),
     file("modules/graphics/src/main/native-glass/lens/cursor/nullCursor"),
     file("modules/graphics/src/main/native-glass/lens/input/android"),
-    file("modules/graphics/src/main/native-glass/lens/wm/screen/androidScreen.c")]
+    file("modules/graphics/src/main/native-glass/lens/wm/screen/androidScreen.c"),
+    file("modules/graphics/src/main/native-glass/lens/platform-util")]
 ANDROID.glass.eglfb.compiler = compiler
 ANDROID.glass.eglfb.linker = linker
 ANDROID.glass.eglfb.lib = "glass_lens_eglfb"
--- a/buildSrc/armv6hf.gradle	Tue Sep 03 12:13:17 2013 -0400
+++ b/buildSrc/armv6hf.gradle	Tue Sep 03 09:40:03 2013 -0700
@@ -291,7 +291,8 @@
     file("modules/graphics/src/main/native-glass/lens/wm"),
     file("modules/graphics/src/main/native-glass/lens/cursor/fbCursor"),
     file("modules/graphics/src/main/native-glass/lens/input/udev"),
-    file("modules/graphics/src/main/native-glass/lens/wm/screen/dfbScreen.c")]
+    file("modules/graphics/src/main/native-glass/lens/wm/screen/dfbScreen.c"),
+    file("modules/graphics/src/main/native-glass/lens/platform-util") ]
     //file("modules/graphics/src/main/native-glass/lens/wm/screen")]
 ARMV6HF.glass.directfb.compiler = compiler
 ARMV6HF.glass.directfb.ccFlags = ["-ffast-math", extraCFlags, "-I$sdk/usr/include/directfb", "-DLINUX"].flatten()
@@ -305,7 +306,8 @@
     file("modules/graphics/src/main/native-glass/lens/wm"),
     file("modules/graphics/src/main/native-glass/lens/cursor/fbCursor"),
     file("modules/graphics/src/main/native-glass/lens/input/udev"),
-    file("modules/graphics/src/main/native-glass/lens/wm/screen/fbdevScreen.c")]
+    file("modules/graphics/src/main/native-glass/lens/wm/screen/fbdevScreen.c"),
+    file("modules/graphics/src/main/native-glass/lens/platform-util") ]
     //file("modules/graphics/src/main/native-glass/lens/wm/screen")]
 ARMV6HF.glass.fb.compiler = compiler
 ARMV6HF.glass.fb.ccFlags = ["-ffast-math", extraCFlags, "-DLINUX"].flatten()
--- a/buildSrc/armv6sf.gradle	Tue Sep 03 12:13:17 2013 -0400
+++ b/buildSrc/armv6sf.gradle	Tue Sep 03 09:40:03 2013 -0700
@@ -323,7 +323,8 @@
     file("modules/graphics/src/main/native-glass/lens/wm"),
     file("modules/graphics/src/main/native-glass/lens/cursor/fbCursor"),
     file("modules/graphics/src/main/native-glass/lens/input/udev"),
-    file("modules/graphics/src/main/native-glass/lens/wm/screen/fbdevScreen.c")]
+    file("modules/graphics/src/main/native-glass/lens/wm/screen/fbdevScreen.c"),
+    file("modules/graphics/src/main/native-glass/lens/platform-util") ]
 ARMV6SF.glass.fb.compiler = compiler
 ARMV6SF.glass.fb.ccFlags = ["-ffast-math", extraCFlags, "-DLINUX"].flatten()
 ARMV6SF.glass.fb.linker = linker
--- a/buildSrc/ios.gradle	Tue Sep 03 12:13:17 2013 -0400
+++ b/buildSrc/ios.gradle	Tue Sep 03 09:40:03 2013 -0700
@@ -111,7 +111,7 @@
     "-miphoneos-version-min=6.0", "-fmessage-length=0", "-std=c99", "-fno-common",
     "-Wall", "-fno-strict-aliasing", "-fwrapv", "-fpascal-strings", "-fobjc-abi-version=2", "-fobjc-legacy-dispatch",
     "-I$JDK_HOME/include", "-I$JDK_HOME/include/darwin", "-c",
-    IS_DEBUG ? "-DDEBUG" : ["-O3", "-DNDEBUG"]].flatten()
+    IS_DEBUG ? ["-O0", "-DDEBUG", "-g"] : ["-O3", "-DNDEBUG"]].flatten()
 
 def compiler = "clang"
 def linker = "libtool"
--- a/modules/controls/src/test/java/javafx/scene/control/TableViewTest.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/controls/src/test/java/javafx/scene/control/TableViewTest.java	Tue Sep 03 09:40:03 2013 -0700
@@ -1805,7 +1805,8 @@
 
         TableColumn<Person,String> first = new TableColumn<Person,String>("first");
         first.setCellValueFactory(new PropertyValueFactory("firstName"));
-        first.setCellFactory(TextFieldTableCell.forTableColumn());
+        Callback<TableColumn<Person, String>, TableCell<Person, String>> factory = TextFieldTableCell.forTableColumn();
+        first.setCellFactory(factory);
         table.getColumns().addAll(first);
         first.setOnEditStart(new EventHandler() {
             @Override public void handle(Event t) {
@@ -1852,7 +1853,8 @@
 
         TableColumn<Person,String> first = new TableColumn<Person,String>("first");
         first.setCellValueFactory(new PropertyValueFactory("firstName"));
-        first.setCellFactory(TextFieldTableCell.forTableColumn());
+        Callback<TableColumn<Person, String>, TableCell<Person, String>> factory = TextFieldTableCell.forTableColumn();
+        first.setCellFactory(factory);
         table.getColumns().addAll(first);
         first.setOnEditStart(new EventHandler() {
             @Override public void handle(Event t) {
--- a/modules/controls/src/test/java/javafx/scene/control/TreeTableViewTest.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/controls/src/test/java/javafx/scene/control/TreeTableViewTest.java	Tue Sep 03 09:40:03 2013 -0700
@@ -2580,7 +2580,8 @@
         treeTableView.setEditable(true);
 
         TreeTableColumn<String, String> col = new TreeTableColumn<>("column");
-        col.setCellFactory(TextFieldTreeTableCell.forTreeTableColumn());
+        Callback<TreeTableColumn<String, String>, TreeTableCell<String, String>> factory = TextFieldTreeTableCell.forTreeTableColumn();
+        col.setCellFactory(factory);
         col.setCellValueFactory(new Callback<TreeTableColumn.CellDataFeatures<String, String>, ObservableValue<String>>() {
             @Override public ObservableValue<String> call(TreeTableColumn.CellDataFeatures<String, String> param) {
                 return new ReadOnlyObjectWrapper<>(param.getValue().getValue());
@@ -2647,7 +2648,8 @@
         new StageLoader(treeTableView);
 
         // now replace the cell factory
-        col.setCellFactory(TextFieldTreeTableCell.forTreeTableColumn());
+        Callback<TreeTableColumn<String, String>, TreeTableCell<String, String>> factory = TextFieldTreeTableCell.forTreeTableColumn();
+        col.setCellFactory(factory);
 
         Toolkit.getToolkit().firePulse();
 
--- a/modules/graphics/src/main/java/com/sun/glass/ui/lens/LensApplication.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/glass/ui/lens/LensApplication.java	Tue Sep 03 09:40:03 2013 -0700
@@ -701,6 +701,40 @@
         }
     }
 
+    /** Posts a mouse event, filtering out sequences of similar motion or drag
+     * events. */
+    private void postMouseEvent(LensView view, int eventType,
+                                int x, int y, int absx, int absy,
+                                int button, int modifiers,
+                                boolean isPopupTrigger, boolean isSynthesized) {
+        synchronized (eventList) {
+            if (!eventList.isEmpty() && (eventType == MouseEvent.DRAG
+                    || eventType == MouseEvent.MOVE)) {
+                Event lastEvent = eventList.getLast();
+                if (lastEvent instanceof LensMouseEvent) {
+                    LensMouseEvent e = (LensMouseEvent) lastEvent;
+                    if (e.target == view
+                            && e.action == eventType
+                            && e.button == button
+                            && e.modifiers == modifiers
+                            && e.isPopupTrigger == isPopupTrigger
+                            && e.isSynthesized == isSynthesized) {
+                        // rewrite the coordinates of the scheduled event with
+                        // the coordinates of this event.
+                        e.x = x;
+                        e.y = y;
+                        e.absx = absx;
+                        e.absy = absy;
+                        return;
+                    }
+                }
+            }
+            postEvent(new LensMouseEvent(view, eventType, x, y, absx, absy,
+                                         button, modifiers, isPopupTrigger,
+                                         isSynthesized));
+        }
+    }
+
     private static class RunLoopControl {
         boolean active; // thread should continue to process events.
         Object release; // object to return with on leave nested
@@ -1106,11 +1140,9 @@
 
             //continue process events only if not already consumed
             if (!handleDragEvents(view, eventType, x, y, absx, absy, button, modifiers)) {
-                postEvent(new LensMouseEvent(view, eventType,
-                                             x, y, absx, absy,
-                                             button, modifiers,
-                                             isPopupTrigger,
-                                             isSynthesized));
+                postMouseEvent(view, eventType, x, y, absx, absy,
+                               button, modifiers,
+                               isPopupTrigger, isSynthesized);
             }
         } catch (Exception e) {
             reportException(e);
@@ -1280,12 +1312,10 @@
                 if (LensLogger.getLogger().isLoggable(Level.FINEST)) {
                     LensLogger.getLogger().finest("Drag detected - sending DRAG event");
                 }
-                postEvent(new LensMouseEvent(view, eventType,
-                                             x, y, absx, absy,
-                                             button,
-                                             modifiers,
-                                             false /*isPopupTrigger*/,
-                                             false /*isSynthesized*/));
+                postMouseEvent(view, eventType, x, y, absx, absy,
+                               button, modifiers,
+                               false /*isPopupTrigger*/,
+                               false /*isSynthesized*/);
                 eventConsumed = true;
 
             }
--- a/modules/graphics/src/main/java/com/sun/javafx/WeakReferenceMap.java	Tue Sep 03 12:13:17 2013 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,133 +0,0 @@
-/*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.sun.javafx;
-
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * This is a helper class for handling weak references across all devices.
- * We tried to use WeakHashMap, but it isn't available on mobile. We tried to
- * add it to mobile, but it requires ReferenceQueue and it appears that
- * ReferenceQueue requires support from the VM which we don't know that we
- * have on mobile. So this class attempts to lessen the likelihood of
- * memory leaks. It is similar to the WeakReferenceQueue class, but specifically
- * has a Map-like interface, even though it does not work based on hashes but
- * rather on iteration based lookup.
- * NOTE: THIS DOES NOT CONFORM TO MAP, BE CAREFUL WHAT YOU CALL!!
- */
-public class WeakReferenceMap implements Map {
-    ArrayList<Entry> queue = new ArrayList<Entry>();
-
-    @SuppressWarnings("unchecked")
-    public Object put(Object key, Object obj) {
-        // remove the specific key rather than calling cleanup(), otherwise 
-        // the entry won't get removed if key is still referenced. In other
-        // words, in the remove function, the call to entry.weakKey.get() 
-        // could return non-null for this key resulting in more than
-        // one entry for this key in the queue.
-        remove(key);
-        Entry entry = new Entry();
-        entry.weakKey = new WeakReference(key);
-        entry.value = obj;
-        queue.add(entry);
-        return obj;
-    }
-
-    public int size() {
-        cleanup();
-        return queue.size();
-    }
-
-    public boolean isEmpty() {
-        cleanup();
-        return queue.isEmpty();
-    }
-
-    public Object remove(Object obj) {
-        for (int i = queue.size() - 1; i >= 0; --i) {
-            Entry entry = queue.get(i);
-            Object other = entry.weakKey.get();
-            if (other == null || other == obj) queue.remove(i);
-        }
-        return obj;
-    }
-
-    void cleanup() {
-        remove(null);
-    }
-
-    public Object get(Object key) {
-        for (int i = queue.size() - 1; i >= 0; --i) {
-            Entry entry = queue.get(i);
-            Object k = entry.weakKey.get();
-            if (k == null) {
-                queue.remove(i);
-            } else {
-                if (k.equals(key)) {
-                    return entry.value;
-                }
-            }
-        }
-        return null;
-    }
-
-    public void clear() {
-        queue.clear();
-    }
-
-    public boolean containsKey(Object key) {
-        throw new UnsupportedOperationException("Not implemented");
-    }
-
-    public boolean containsValue(Object value) {
-        throw new UnsupportedOperationException("Not implemented");
-    }
-
-    public Set keySet() {
-        throw new UnsupportedOperationException("Not implemented");
-    }
-
-    public Collection values() {
-        throw new UnsupportedOperationException("Not implemented");
-    }
-
-    public Set entrySet() {
-        throw new UnsupportedOperationException("Not implemented");
-    }
-
-    public void putAll(Map m) {
-        throw new UnsupportedOperationException("Not implemented");
-    }
-
-    private static final class Entry {
-        WeakReference weakKey;
-        Object value;
-    }
-}
--- a/modules/graphics/src/main/java/com/sun/javafx/geom/transform/Affine3D.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/geom/transform/Affine3D.java	Tue Sep 03 09:40:03 2013 -0700
@@ -41,8 +41,6 @@
     private double mzz;
     private double mzt;
 
-    private Vec3d tempV3d = new Vec3d();
-
     public Affine3D() {
         mxx = myy = mzz = 1.0;
 //        mxy = mxz = mxt = 0.0;  /* Not needed. */
@@ -328,6 +326,7 @@
             case (APPLY_SHEAR | APPLY_TRANSLATE):
             /* NOBREAK */
             case (APPLY_SHEAR):
+                Vec3d tempV3d = new Vec3d();
                 dst = TransformHelper.general3dBoundsTransform(this, src, dst, tempV3d);
                 break;
             case (APPLY_SCALE | APPLY_TRANSLATE):
--- a/modules/graphics/src/main/java/com/sun/javafx/scene/DirtyBits.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/scene/DirtyBits.java	Tue Sep 03 09:40:03 2013 -0700
@@ -93,6 +93,9 @@
     MESH,
     MESH_GEOM,
 
+    // Used for any debug information we want to sync down.
+    DEBUG,
+
     // NOTE: The following MUST be the last enum value in this class. The ordinal
     // of this enum indicates the number of dirty bits in this set, exclusive of
     // the MAX_DIRTY bit itself, which will never be set or tested.
--- a/modules/graphics/src/main/java/com/sun/javafx/sg/prism/NGGroup.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/sg/prism/NGGroup.java	Tue Sep 03 09:40:03 2013 -0700
@@ -191,14 +191,11 @@
 
     @Override
     protected void renderContent(Graphics g) {
-        renderChildren(g, (NodePath<NGNode>)g.getRenderRoot());
-    }
-
-    private void renderChildren(Graphics g, NodePath<NGNode> renderRoot) {
         if (children == null) {
             return;
         }
 
+        NodePath renderRoot = g.getRenderRoot();
         int startPos = 0;
         if (renderRoot != null) {
             if (renderRoot.hasNext()) {
@@ -309,7 +306,7 @@
      *                                                                         *
      **************************************************************************/
     @Override
-    protected RenderRootResult computeRenderRoot(NodePath<NGNode> path, RectBounds dirtyRegion, int cullingIndex, BaseTransform tx,
+    protected RenderRootResult computeRenderRoot(NodePath path, RectBounds dirtyRegion, int cullingIndex, BaseTransform tx,
                                        GeneralTransform3D pvTx) {
 
         // If the NGGroup is completely outside the culling area, then we don't have to traverse down
@@ -317,7 +314,7 @@
         if (cullingIndex != -1) {
             final int bits = cullingBits >> (cullingIndex*2);
             if ((bits & DIRTY_REGION_CONTAINS_OR_INTERSECTS_NODE_BOUNDS) == 0) {
-                return RenderRootResult.NONE;
+                return RenderRootResult.NO_RENDER_ROOT;
             }
             if ((bits & DIRTY_REGION_CONTAINS_NODE_BOUNDS) != 0) {
                 cullingIndex = -1; // Do not check culling in children,
@@ -326,26 +323,25 @@
         }
 
         if (!isVisible()) {
-            return RenderRootResult.NONE;
+            return RenderRootResult.NO_RENDER_ROOT;
         }
 
         if (getOpacity() != 1.0 || (getEffect() != null && getEffect().reducesOpaquePixels()) || needsBlending()) {
-            return RenderRootResult.NONE;
+            return RenderRootResult.NO_RENDER_ROOT;
         }
 
         if (getClipNode() != null) {
             final NGNode clip = getClipNode();
             RectBounds clipBounds = clip.getOpaqueRegion();
             if (clipBounds == null) {
-                return RenderRootResult.NONE;
+                return RenderRootResult.NO_RENDER_ROOT;
             }
             TEMP_TRANSFORM.deriveWithNewTransform(tx).deriveWithConcatenation(getTransform()).deriveWithConcatenation(clip.getTransform());
             if (!checkBoundsInQuad(clipBounds, dirtyRegion, TEMP_TRANSFORM, pvTx)) {
-                return RenderRootResult.NONE;
+                return RenderRootResult.NO_RENDER_ROOT;
             }
         }
 
-
         // An NGGroup itself never draws pixels, so we don't have to call super. Just visit
         // each child, starting with the top-most.
         double mxx = tx.getMxx();
@@ -363,24 +359,39 @@
         double mzz = tx.getMzz();
         double mzt = tx.getMzt();
         final BaseTransform chTx = tx.deriveWithConcatenation(getTransform());
-        RenderRootResult result = RenderRootResult.NONE;
-        int resultIdx;
+
+        // We need to keep a reference to the result of calling computeRenderRoot on each child
+        RenderRootResult result = RenderRootResult.NO_RENDER_ROOT;
+        // True if every child _after_ the the found render root is clean
         boolean followingChildrenClean = true;
-        for (resultIdx=children.size()-1; resultIdx>=0; resultIdx--) {
+        // Iterate over all children, looking for a render root.
+        for (int resultIdx=children.size()-1; resultIdx>=0; resultIdx--) {
+            // Get the render root result from the child
             final NGNode child = children.get(resultIdx);
             result = child.computeRenderRoot(path, dirtyRegion, cullingIndex, chTx, pvTx);
-            if (result != RenderRootResult.NONE) break;
+            // Update this flag, which if true means that this child and all subsequent children
+            // of this group are all clean.
             followingChildrenClean &= child.isClean();
+
+            if (result == RenderRootResult.HAS_RENDER_ROOT) {
+                // If we have a render root and it is dirty, then we don't really care whether
+                // followingChildrenClean is true or false, we just add this group to the
+                // path and we're done.
+                path.add(this);
+                break;
+            } else if (result == RenderRootResult.HAS_RENDER_ROOT_AND_IS_CLEAN) {
+                path.add(this);
+                // If we have a result which is itself reporting that it is clean, but
+                // we have some following children which are dirty, then we need to
+                // switch the result for this Group to be HAS_RENDER_ROOT.
+                if (!followingChildrenClean) {
+                    result = RenderRootResult.HAS_RENDER_ROOT;
+                }
+                break;
+            }
         }
         // restore previous transform state
         tx.restoreTransform(mxx, mxy, mxz, mxt, myx, myy, myz, myt, mzx, mzy, mzz, mzt);
-        if (result != RenderRootResult.NONE) {
-            if (result == RenderRootResult.HAS_RENDER_ROOT || dirty != DirtyFlag.CLEAN ||
-                    (childDirty && !followingChildrenClean)) {
-                path.add(this);
-                result = RenderRootResult.HAS_RENDER_ROOT;
-            }
-        }
         return result;
     }
 
@@ -430,39 +441,16 @@
     }
 
     @Override
-    public void drawCullBits(Graphics g) {
-        if (getParent() != null) {
-            super.drawCullBits(g);
-        }
-        if (cullingBits != 0) {
-            // save current transform state
-            BaseTransform prevXform = g.getTransformNoClone();
-
-            double mxx = prevXform.getMxx();
-            double mxy = prevXform.getMxy();
-            double mxz = prevXform.getMxz();
-            double mxt = prevXform.getMxt();
-
-            double myx = prevXform.getMyx();
-            double myy = prevXform.getMyy();
-            double myz = prevXform.getMyz();
-            double myt = prevXform.getMyt();
-
-            double mzx = prevXform.getMzx();
-            double mzy = prevXform.getMzy();
-            double mzz = prevXform.getMzz();
-            double mzt = prevXform.getMzt();
-
-            g.transform(getTransform());
-            NGNode child;
-            for (int chldIdx = 0; chldIdx < children.size(); chldIdx++) {
-                child = children.get(chldIdx);
-                child.drawCullBits(g);
-            }
-            // restore previous transform state
-            g.setTransform3D(mxx, mxy, mxz, mxt,
-                             myx, myy, myz, myt,
-                             mzx, mzy, mzz, mzt);
+    public void drawDirtyOpts(final BaseTransform tx, final GeneralTransform3D pvTx,
+                              Rectangle clipBounds, int[] countBuffer, int dirtyRegionIndex) {
+        super.drawDirtyOpts(tx, pvTx, clipBounds, countBuffer, dirtyRegionIndex);
+        // Not really efficient but this code is only executed during debug. This makes sure
+        // that the source transform (tx) is not modified.
+        BaseTransform clone = tx.copy();
+        clone = clone.deriveWithConcatenation(getTransform());
+        for (int childIndex = 0; childIndex < children.size(); childIndex++) {
+            final NGNode child = children.get(childIndex);
+            child.drawDirtyOpts(clone, pvTx, clipBounds, countBuffer, dirtyRegionIndex);
         }
     }
 
--- a/modules/graphics/src/main/java/com/sun/javafx/sg/prism/NGNode.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/sg/prism/NGNode.java	Tue Sep 03 09:40:03 2013 -0700
@@ -26,6 +26,7 @@
 package com.sun.javafx.sg.prism;
 
 import javafx.scene.CacheHint;
+import java.util.ArrayList;
 import java.util.List;
 import com.sun.glass.ui.Screen;
 import com.sun.javafx.geom.BaseBounds;
@@ -45,7 +46,6 @@
 import com.sun.prism.RTTexture;
 import com.sun.prism.ReadbackGraphics;
 import com.sun.prism.impl.PrismSettings;
-import com.sun.prism.paint.Color;
 import com.sun.scenario.effect.Blend;
 import com.sun.scenario.effect.Effect;
 import com.sun.scenario.effect.FilterContext;
@@ -100,14 +100,17 @@
     private final static Boolean effectsSupported =
         (pipeline == null ? false : pipeline.isEffectSupported());
 
-    protected static enum DirtyFlag {
+    public static enum DirtyFlag {
         CLEAN,
         // Means that the node is dirty, but only because of translation
         DIRTY_BY_TRANSLATION,
         DIRTY
     }
 
-    public boolean debug = false;
+    /**
+     * Used for debug purposes. Set during sync.
+     */
+    private String name;
 
     /**
      * Temporary bounds for use by this class or subclasses, designed to
@@ -265,6 +268,16 @@
      */
     private boolean opaqueRegionInvalid = true;
 
+    /**
+     * Used for debug purposes. This field will keep track of which nodes were
+     * rendered as a result of different dirty regions. These correspond to the
+     * same positions as the cullingBits. So for example, if a node was rendered
+     * by dirty region 0, then painted will have the lowest bit set. If it
+     * was rendered by dirty region 3, then it would have the 3rd bit from the
+     * right set ( that is, 1 << 2)
+     */
+    private int painted = 0;
+
     protected NGNode() { }
 
     /***************************************************************************
@@ -609,6 +622,20 @@
         this.isClip = isClip;
     }
 
+    /**
+     * Used for debug purposes.
+     */
+    public final void setName(String value) {
+        this.name = value;
+    }
+
+    /**
+     * Used for debug purposes.
+     */
+    public final String getName() {
+        return name;
+    }
+
     protected final Effect getEffect() { return effectFilter == null ? null : effectFilter.getEffect(); }
 
     /**
@@ -864,6 +891,20 @@
         dirtyChildrenAccumulated = 0;
     }
 
+    /**
+     * Walks down the tree clearing the "painted" bits for each node. This is only
+     * called if we're drawing dirty rectangles or overdraw rectangles.
+     */
+    public void clearPainted() {
+        painted = 0;
+        if (this instanceof NGGroup) {
+            List<NGNode> children = ((NGGroup)this).getChildren();
+            for (int i=0; i<children.size(); i++) {
+                children.get(i).clearPainted();
+            }
+        }
+    }
+
     public void clearDirtyTree() {
         clearDirty();
         if (getClipNode() != null) {
@@ -1354,27 +1395,179 @@
             clearDirtyTree();
         }
 
-        if (debug) {
-            System.out.printf("%s bits: %s bounds: %s\n",
-                this, Integer.toBinaryString(cullingBits), TEMP_RECT_BOUNDS);
+//        System.out.printf("%s bits: %s bounds: %s\n",
+//            this, Integer.toBinaryString(cullingBits), TEMP_RECT_BOUNDS);
+    }
+
+    /**
+     * Fills the given StringBuilder with text representing the structure of the NG graph insofar as dirty
+     * opts is concerned. Used for debug purposes. This is typically called on the root node. The List of
+     * roots is the list of dirty roots as determined by successive calls to getRenderRoot for each dirty
+     * region. The output will be prefixed with a key indicating how to interpret the printout.
+     *
+     * @param s A StringBuilder to fill with the output.
+     * @param roots The list of render roots (may be empty, must not be null).
+     */
+    public final void printDirtyOpts(StringBuilder s, List<NGNode> roots) {
+        s.append("\n*=Render Root\n");
+        s.append("d=Dirty\n");
+        s.append("dt=Dirty By Translation\n");
+        s.append("i=Dirty Region Intersects the NGNode\n");
+        s.append("c=Dirty Region Contains the NGNode\n");
+        s.append("ef=Effect Filter\n");
+        s.append("cf=Cache Filter\n");
+        s.append("cl=This node is a clip node\n");
+        s.append("b=Blend mode is set\n");
+        s.append("or=Opaque Region\n");
+        printDirtyOpts(s, this, BaseTransform.IDENTITY_TRANSFORM, "", roots);
+    }
+
+    /**
+     * Used for debug purposes. Recursively visits all NGNodes and prints those that are possibly part of
+     * the render operation and annotates each node.
+     *
+     * @param s The String builder
+     * @param node The node that we're printing out information about
+     * @param tx The transform
+     * @param prefix Some prefix to put in front of the node output (mostly spacing)
+     * @param roots The different dirty roots, if any.
+     */
+    private final void printDirtyOpts(StringBuilder s, NGNode node, BaseTransform tx, String prefix, List<NGNode> roots) {
+        if (!node.isVisible() || node.getOpacity() == 0) return;
+
+        BaseTransform copy = tx.copy();
+        copy = copy.deriveWithConcatenation(node.getTransform());
+        List<String> stuff = new ArrayList<>();
+        for (int i=0; i<roots.size(); i++) {
+            NGNode root = roots.get(i);
+            if (node == root) stuff.add("*" + i);
+        }
+
+        if (node.dirty != NGNode.DirtyFlag.CLEAN) {
+            stuff.add(node.dirty == NGNode.DirtyFlag.DIRTY ? "d" : "dt");
+        }
+
+        if (node.cullingBits != 0) {
+            int mask = 0x11;
+            for (int i=0; i<15; i++) {
+                int bits = node.cullingBits & mask;
+                if (bits != 0) {
+                    stuff.add(bits == 1 ? "i" + i : bits == 0 ? "c" + i : "ci" + i);
+                }
+                mask = mask << 2;
+            }
+        }
+
+        if (node.effectFilter != null) stuff.add("ef");
+        if (node.cacheFilter != null) stuff.add("cf");
+        if (node.nodeBlendMode != null) stuff.add("b");
+
+        RectBounds opaqueRegion = node.getOpaqueRegion();
+        if (opaqueRegion != null) {
+            RectBounds or = new RectBounds();
+            copy.transform(opaqueRegion, or);
+            stuff.add("or=" + or.getMinX() + ", " + or.getMinY() + ", " + or.getWidth() + ", " + or.getHeight());
+        }
+
+        if (stuff.isEmpty()) {
+            s.append(prefix + node.name + "\n");
+        } else {
+            String postfix = " [";
+            for (int i=0; i<stuff.size(); i++) {
+                postfix = postfix + stuff.get(i);
+                if (i < stuff.size() - 1) postfix += " ";
+            }
+            s.append(prefix + node.name + postfix + "]\n");
+        }
+
+        if (node.getClipNode() != null) {
+            printDirtyOpts(s, node.getClipNode(), copy, prefix + "  cl ", roots);
+        }
+
+        if (node instanceof NGGroup) {
+            NGGroup g = (NGGroup)node;
+            for (int i=0; i<g.getChildren().size(); i++) {
+                printDirtyOpts(s, g.getChildren().get(i), copy, prefix + "  ", roots);
+            }
         }
     }
 
     /**
-     * Helper method draws culling bits for each node.
-     * @param g Graphics.
+     * Helper method draws rectangles indicating the overdraw rectangles.
+     *
+     * @param tx The scene->parent transform.
+     * @param pvTx The perspective camera transform.
+     * @param clipBounds The bounds in scene coordinates
+     * @param colorBuffer A pixel array where each pixel contains a color indicating how many times
+     *                    it has been "drawn"
+     * @param dirtyRegionIndex the index of the dirty region we're gathering information for. This is
+     *                         needed so we can shift the "painted" field to find out if this node
+     *                         was drawn in this dirty region.
      */
-    public void drawCullBits(Graphics g) {
-        if (cullingBits == 0){
-            g.setPaint(new Color(0, 0, 0, .3f));
-        } else {
-            g.setPaint(new Color(0, 1, 0, .3f));
+    public void drawDirtyOpts(final BaseTransform tx, final GeneralTransform3D pvTx,
+                              Rectangle clipBounds, int[] colorBuffer, int dirtyRegionIndex) {
+        if ((painted & (1 << (dirtyRegionIndex * 2))) != 0) {
+            // Transforming the content bounds (which includes the clip) to screen coordinates
+            tx.copy().deriveWithConcatenation(getTransform()).transform(contentBounds, TEMP_BOUNDS);
+            if (pvTx != null) pvTx.transform(TEMP_BOUNDS, TEMP_BOUNDS);
+            RectBounds bounds = new RectBounds();
+            TEMP_BOUNDS.flattenInto(bounds);
+
+            // Adjust the bounds so that they are relative to the clip. The colorBuffer is sized
+            // exactly the same as the clip, and the elements of the colorBuffer represent the
+            // pixels inside the clip. However the bounds of this node may overlap the clip in
+            // some manner, so we adjust them such that x, y, w, h will be the adjusted bounds.
+            assert clipBounds.width * clipBounds.height == colorBuffer.length;
+            bounds.intersectWith(clipBounds);
+            int x = (int) bounds.getMinX() - clipBounds.x;
+            int y = (int) bounds.getMinY() - clipBounds.y;
+            int w = (int) (bounds.getWidth() + .5);
+            int h = (int) (bounds.getHeight() + .5);
+
+            if (w == 0 || h == 0) {
+                // I would normally say we should never reach this point, as it means something was
+                // marked as painted but really couldn't have been.
+                return;
+            }
+
+            // x, y, w, h are 0 based and will fit within the clip, so now we can simply update
+            // all the pixels that fall within these bounds.
+            for (int i = y; i < y+h; i++) {
+                for (int j = x; j < x+w; j++) {
+                    final int index = i * clipBounds.width + j;
+                    int color = colorBuffer[index];
+
+                    // This is kind of a dirty hack. The idea is to show green if 0 or 1
+                    // times a pixel is drawn, Yellow for 2 or 3 times, and red for more
+                    // Than that. So I use 0x80007F00 as the first green color, and
+                    // 0x80008000 as the second green color, but their so close to the same
+                    // thing you probably won't be able to tell them apart, but I can tell
+                    // numerically they're different and increment (so I use the colors
+                    // as my counters).
+                    if (color == 0) {
+                        color = 0x8007F00;
+                    } else if ((painted & (3 << (dirtyRegionIndex * 2))) == 3) {
+                        switch (color) {
+                            case 0x80007F00:
+                                color = 0x80008000;
+                                break;
+                            case 0x80008000:
+                                color = 0x807F7F00;
+                                break;
+                            case 0x807F7F00:
+                                color = 0x80808000;
+                                break;
+                            case 0x80808000:
+                                color = 0x807F0000;
+                                break;
+                            default:
+                                color = 0x80800000;
+                        }
+                    }
+                    colorBuffer[index] = color;
+                }
+            }
         }
-        g.fillRect(
-                transformedBounds.getMinX(),
-                transformedBounds.getMinY(),
-                transformedBounds.getWidth(),
-                transformedBounds.getHeight());
     }
 
     /***************************************************************************
@@ -1384,24 +1577,32 @@
      **************************************************************************/
     protected static enum RenderRootResult {
         /**
-         * The computation to determine whether a branch of the scene graph has
-         * a render root has concluded that indeed, there is one.
+         * A Node returns NO_RENDER_ROOT when it is not a render root because
+         * it does not have an opaqueRegion which completely covers the area
+         * of the clip. Maybe the node is dirty, but outside the dirty region
+         * that we're currently processing. For an NGGroup, returning
+         * NO_RENDER_ROOT means that there is no render root (occluder) within
+         * this entire branch of the tree.
+         */
+        NO_RENDER_ROOT,
+        /**
+         * A Node returns HAS_RENDER_ROOT when its opaque region completely
+         * covers the clip. An NGGroup returns HAS_RENDER_ROOT when one of
+         * its children either returned HAS_RENDER_ROOT or HAS_RENDER_ROOT_AND_IS_CLEAN.
          */
         HAS_RENDER_ROOT,
         /**
-         * A RenderRootResult of this value means that although we discovered a
-         * render root, we also determined that there were no dirty nodes that
-         * followed the render root. Therefore, we don't actually have to render
-         * anything (the only dirty nodes are completely occluded by clean
-         * nodes).
+         * A Node returns HAS_RENDER_ROOT_AND_IS_CLEAN when its opaque region
+         * completely covers the clip and the Node is, itself, clean. An NGNode
+         * returns HAS_RENDER_ROOT_AND_IS_CLEAN only if it had a child that
+         * returned HAS_RENDER_ROOT_AND_IS_CLEAN and none of its children drawn
+         * above the render root are dirty.
+         *
+         * This optimization allows us to recognize situations where perhaps there
+         * were some dirty nodes, but they are completely covered by an occluder,
+         * and therefore we don't actually have to draw anything.
          */
-        EXISTS_BUT_NOT_DIRTY,
-        /**
-         * Represents the case where we did not find an opaque node that covered
-         * the dirty region, and thus we must start rendering from the actual
-         * root of the hierarchy.
-         */
-        NONE
+        HAS_RENDER_ROOT_AND_IS_CLEAN,
     }
 
     /**
@@ -1414,8 +1615,8 @@
      *
      * @param path node path to store the node path
      */
-    public final void getRenderRoot(NodePath<NGNode> path, RectBounds dirtyRegion, int cullingIndex,
-                                                BaseTransform tx, GeneralTransform3D pvTx) {
+    public final void getRenderRoot(NodePath path, RectBounds dirtyRegion, int cullingIndex,
+                                    BaseTransform tx, GeneralTransform3D pvTx) {
 
         // This is the main entry point, make sure to check these inputs for validity
         if (path == null || dirtyRegion == null || tx == null || pvTx == null) {
@@ -1429,23 +1630,34 @@
         // for that because NGNode doesn't have a reference to the scene it is a part of...
 
         RenderRootResult result = computeRenderRoot(path, dirtyRegion, cullingIndex, tx, pvTx);
-        if (result == RenderRootResult.NONE) {
-            //Render from the root
+        if (result == RenderRootResult.NO_RENDER_ROOT) {
+            // We didn't find any render root, which means that no one node was large enough
+            // to obscure the entire dirty region (or, possibly, some combination of nodes in an
+            // NGGroup were not, together, large enough to do the job). So we need to render
+            // from the root node, which is this node.
             path.add(this);
+        } else if (result == RenderRootResult.HAS_RENDER_ROOT_AND_IS_CLEAN) {
+            // We've found a render root, and it is clean and everything above it in painter order
+            // is clean, so actually we have nothing to paint this time around (some stuff must
+            // have been dirty which is completely occluded by the render root). So we can clear
+            // the path, which indicates to the caller that nothing needs to be painted.
+            path.clear();
         }
     }
 
     /**
-     * Searches for the last node that covers all of the specified dirty region with opaque region,
-     * in this node's subtree.
-     * Such node can serve as a rendering root as all nodes preceding the node will be covered by it.
+     * Searches for the last node that covers all of the specified dirty region with an opaque region,
+     * in this node's subtree. Such a node can serve as a rendering root as all nodes preceding the node
+     * will be covered by it.
+     *
+     * @param path the NodePath to populate with the path to the render root. Cannot be null.
      * @param dirtyRegion the current dirty region. Cannot be null.
      * @param cullingIndex index of culling information
      * @param tx current transform. Cannot be null.
      * @param pvTx current perspective transform. Cannot be null.
-     * @return New rendering root or null if no such node exists in this subtree
+     * @return The result of visiting this node.
      */
-    RenderRootResult computeRenderRoot(NodePath<NGNode> path, RectBounds dirtyRegion,
+    RenderRootResult computeRenderRoot(NodePath path, RectBounds dirtyRegion,
                                        int cullingIndex, BaseTransform tx, GeneralTransform3D pvTx) {
         return computeNodeRenderRoot(path, dirtyRegion, cullingIndex, tx, pvTx);
     }
@@ -1482,13 +1694,17 @@
 
     /**
      * Check if this node can serve as rendering root for this dirty region.
+     *
+     * @param path the NodePath to populate with the path to the render root. Cannot be null.
      * @param dirtyRegion the current dirty region. Cannot be null.
      * @param cullingIndex index of culling information, -1 means culling information should not be used
      * @param tx current transform. Cannot be null.
      * @param pvTx current perspective transform. Cannot be null.
-     * @return this node if this node's opaque region covers the specified dirty region. Null otherwise.
+     * @return NO_RENDER_ROOT if this node does <em>not</em> have an opaque
+     *         region that fills the entire dirty region. Returns HAS_RENDER_ROOT
+     *         if the opaque region fills the dirty region.
      */
-    final RenderRootResult computeNodeRenderRoot(NodePath<NGNode> path, RectBounds dirtyRegion,
+    final RenderRootResult computeNodeRenderRoot(NodePath path, RectBounds dirtyRegion,
                                                  int cullingIndex, BaseTransform tx, GeneralTransform3D pvTx) {
 
         // Nodes outside of the dirty region can be excluded immediately.
@@ -1496,17 +1712,16 @@
         if (cullingIndex != -1) {
             final int bits = cullingBits >> (cullingIndex * 2);
             if ((bits & DIRTY_REGION_CONTAINS_OR_INTERSECTS_NODE_BOUNDS) == 0x00) {
-                return RenderRootResult.NONE;
+                return RenderRootResult.NO_RENDER_ROOT;
             }
         }
 
         if (!isVisible()) {
-            return RenderRootResult.NONE;
+            return RenderRootResult.NO_RENDER_ROOT;
         }
 
-
         final RectBounds opaqueRegion = getOpaqueRegion();
-        if (opaqueRegion == null) return RenderRootResult.NONE;
+        if (opaqueRegion == null) return RenderRootResult.NO_RENDER_ROOT;
 
         final BaseTransform localToParentTx = getTransform();
 
@@ -1518,16 +1733,12 @@
         // that each corner of the dirty region lies within the (potentially rotated) quad
         // of the opaqueRegion.
         if (checkBoundsInQuad(opaqueRegion, dirtyRegion, localToSceneTx, pvTx)) {
-            // We have the potential render root, now check if it needs to be rendered
-            if (dirty != DirtyFlag.CLEAN || childDirty) {
-                path.add(this);
-                return RenderRootResult.HAS_RENDER_ROOT;
-            } else {
-                return RenderRootResult.EXISTS_BUT_NOT_DIRTY;
-            }
+            // This node is a render root.
+            path.add(this);
+            return isClean() ? RenderRootResult.HAS_RENDER_ROOT_AND_IS_CLEAN : RenderRootResult.HAS_RENDER_ROOT;
         }
 
-        return RenderRootResult.NONE;
+        return RenderRootResult.NO_RENDER_ROOT;
     }
 
     static boolean checkBoundsInQuad(RectBounds untransformedQuad,
@@ -1582,7 +1793,7 @@
      * Gets the opaque region for this node, if there is one, or returns null.
      * @return The opaque region for this node, or null.
      */
-    final RectBounds getOpaqueRegion() {
+    public final RectBounds getOpaqueRegion() {
         // Note that when we invalidate the opaqueRegion of an NGNode, we don't
         // walk up the tree or communicate with the parents (unlike dirty flags).
         // An NGGroup does not compute an opaqueRegion based on the union of opaque
@@ -1715,13 +1926,10 @@
      */
     public final void render(Graphics g) {
         if (PULSE_LOGGING_ENABLED) PULSE_LOGGER.renderIncrementCounter("Nodes visited during render");
-        if (debug) System.out.println("render called on " + getClass().getSimpleName());
         // Clear the visuals changed flag
         clearDirty();
         // If it isn't visible, then punt
         if (!visible || opacity == 0f) return;
-        // If we are supposed to cull, then go ahead and do so
-//        if (cull(clip, tx)) return;
 
         // We know that we are going to render this node, so we call the
         // doRender method, which subclasses implement to do the actual
@@ -1797,18 +2005,30 @@
         // The clip must be below the cache filter, as this is expected in the
         // CacheFilter in order to apply scrolling optimization
         g.transform(getTransform());
+        // Try to keep track of whether this node was *really* painted. Still an
+        // approximation, but somewhat more accurate (at least it doesn't include
+        // groups which don't paint anything themselves).
+        boolean p = false;
         if (g instanceof ReadbackGraphics && needsBlending()) {
             renderNodeBlendMode(g);
+            p = true;
         } else if (getOpacity() < 1f) {
             renderOpacity(g);
+            p = true;
         } else if (getCacheFilter() != null) {
             renderCached(g);
+            p = true;
         } else if (getClipNode() != null) {
             renderClip(g);
+            p = true;
         } else if (getEffectFilter() != null && effectsSupported) {
             renderEffect(g);
+            p = true;
         } else {
             renderContent(g);
+            if (PrismSettings.showOverdraw) {
+                p = this instanceof NGRegion || !(this instanceof NGGroup);
+            }
         }
 
         if (preCullingTurnedOff) {
@@ -1824,6 +2044,18 @@
         g.setDepthTest(prevDepthTest);
 
         if (PULSE_LOGGING_ENABLED) PULSE_LOGGER.renderIncrementCounter("Nodes rendered");
+
+        // Used for debug purposes. This is not entirely accurate, as it doesn't measure the
+        // number of times this node drew to the pixels, and in some cases reports a node as
+        // having been drawn even when it didn't lay down any pixels. We'd need to integrate
+        // with our shaders or do something much more invasive to get better data here.
+        if (PrismSettings.showOverdraw) {
+            if (p) {
+                painted |= 3 << (g.getClipRectIndex() * 2);
+            } else {
+                painted |= 1 << (g.getClipRectIndex() * 2);
+            }
+        }
     }
 
     /**
@@ -2186,6 +2418,10 @@
     public void release() {
     }
 
+    @Override public String toString() {
+        return name == null ? super.toString() : name;
+    }
+
     public void applyTransform(final BaseTransform tx, DirtyRegionContainer drc) {
         for (int i = 0; i < drc.size(); i++) {
             drc.setDirtyRegion(i, (RectBounds) tx.transform(drc.getDirtyRegion(i), drc.getDirtyRegion(i)));
--- a/modules/graphics/src/main/java/com/sun/javafx/sg/prism/NGRegion.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/sg/prism/NGRegion.java	Tue Sep 03 09:40:03 2013 -0700
@@ -229,8 +229,14 @@
         this.width = width;
         this.height = height;
         invalidateOpaqueRegion();
-        backgroundInsets = null;
         cacheKey = null;
+        // We only have to clear the background insets when the size changes if the
+        // background has fills who's insets are dependent on the size (as would be
+        // true only if a CornerRadii of any background fill on the background had
+        // a percentage based radius).
+        if (background != null && background.isFillPercentageBased()) {
+            backgroundInsets = null;
+        }
     }
 
     /**
@@ -239,10 +245,10 @@
      *
      * @param b Border, of type javafx.scene.layout.Border
      */
-    public void updateBorder(Object b) {
+    public void updateBorder(Border b) {
         // Make sure that the border instance we store on this NGRegion is never null
         final Border old = border;
-        border = b == null ? Border.EMPTY : (Border) b;
+        border = b == null ? Border.EMPTY : b;
 
         // Determine whether the geometry has changed, or if only the visuals have
         // changed. Geometry changes will require more work, and an equals check
@@ -262,10 +268,10 @@
      *
      * @param b    Background, of type javafx.scene.layout.Background. Can be null.
      */
-    public void updateBackground(Object b) {
+    public void updateBackground(Background b) {
         // Make sure that the background instance we store on this NGRegion is never null
         final Background old = background;
-        background = b == null ? Background.EMPTY : (Background) b;
+        background = b == null ? Background.EMPTY : b;
 
         final List<BackgroundFill> fills = background.getFills();
         cacheMode = 0;
@@ -362,11 +368,11 @@
      *                                                                        *
      *************************************************************************/
 
-    private RegionImageCache getImageCache(Graphics g) {
-        Screen screen = g.getAssociatedScreen();
+    private RegionImageCache getImageCache(final Graphics g) {
+        final Screen screen = g.getAssociatedScreen();
         RegionImageCache cache = imageCacheMap.get(screen);
         if (cache == null) {
-            cache = new RegionImageCache(g);
+            cache = new RegionImageCache(g.getResourceFactory());
             imageCacheMap.put(screen, cache);
         }
         return cache;
@@ -407,14 +413,12 @@
         return (RectBounds) opaqueRegion.deriveWithNewBounds(opaqueLeft, opaqueTop, 0, width - opaqueRight, height - opaqueBottom, 0);
     }
 
-    @Override protected RenderRootResult computeRenderRoot(NodePath<NGNode> path, RectBounds dirtyRegion,
+    @Override protected RenderRootResult computeRenderRoot(NodePath path, RectBounds dirtyRegion,
                                                            int cullingIndex, BaseTransform tx,
                                                            GeneralTransform3D pvTx) {
 
         RenderRootResult result = super.computeRenderRoot(path, dirtyRegion, cullingIndex, tx, pvTx);
-        if (result == RenderRootResult.HAS_RENDER_ROOT) {
-            path.add(this);
-        } else if (result == RenderRootResult.NONE){
+        if (result == RenderRootResult.NO_RENDER_ROOT){
             result = computeNodeRenderRoot(path, dirtyRegion, cullingIndex, tx, pvTx);
         }
         return result;
@@ -445,11 +449,10 @@
      *************************************************************************/
 
     @Override protected void renderContent(Graphics g) {
-        // Use Effect to render 3D transformed Region that does not contain 3D
-        // transformed children.
-        // This is done in order to render the Region's content and children
-        // into an image in local coordinates using the identity transform.
-        // The resulting image will then be correctly transformed in 3D by
+        // Use Effect to render a 3D transformed Region that does not contain 3D
+        // transformed children. This is done in order to render the Region's
+        // content and children into an image in local coordinates using the identity
+        // transform. The resulting image will then be correctly transformed in 3D by
         // the composite transform used to render this Region.
         // However, we avoid doing this for Regions whose children have a 3D
         // transform, because it will flatten the transforms of those children
@@ -560,9 +563,9 @@
             if (!background.isEmpty()) {
                 // cacheWidth is the width of the region used within the cached image. For example,
                 // perhaps normally the width of a region is 200px. But instead I will render the
-                // region as though it is 20px wide instead into the cached image. 20px in this
-                // case is the cache width. Although it may draw into more pixels than this (for
-                // example, drawing the focus rectangle extends beyond the width of the region).
+                // region as though it is 20px wide into the cached image. 20px in this case is
+                // the cache width. Although it may draw into more pixels than this (for example,
+                // drawing the focus rectangle extends beyond the width of the region).
                 // left + right background insets give us the left / right slice locations, plus 1 pixel for the center.
                 // Round the whole thing up to be a whole number.
                 if (backgroundInsets == null) updateBackgroundInsets();
@@ -600,8 +603,6 @@
                 // will not look the same as though drawn by vector
                 final boolean cache =
                         background.getFills().size() > 1 && // Not worth the overhead otherwise
-                        width == (int)width &&
-                        height == (int)height &&
                         cacheMode != 0 &&
                         g.getTransformNoClone().isTranslateOrIdentity();
                 RTTexture cached = null;
@@ -651,52 +652,59 @@
                     final float srcX2 = srcX1 + textureWidth;
                     final float srcY2 = srcY1 + textureHeight;
 
+                    // If total destination width is < the source width, then we need to start
+                    // shrinking the left and right sides to accommodate. Likewise in the other dimension.
+                    double adjustedLeftInset = leftInset;
+                    double adjustedRightInset = rightInset;
+                    double adjustedTopInset = topInset;
+                    double adjustedBottomInset = bottomInset;
+                    if (leftInset + rightInset > width) {
+                        double fraction = width / (leftInset + rightInset);
+                        adjustedLeftInset *= fraction;
+                        adjustedRightInset *= fraction;
+                    }
+                    if (topInset + bottomInset > height) {
+                        double fraction = height / (topInset + bottomInset);
+                        adjustedTopInset *= fraction;
+                        adjustedBottomInset *= fraction;
+                    }
+
                     if (sameWidth && sameHeight) {
                         g.drawTexture(cached, dstX1, dstY1, dstX2, dstY2, srcX1, srcY1, srcX2, srcY2);
                     } else if (sameHeight) {
                         // We do 3-patch rendering fixed height
-                        final float left = (float) (leftInset + outsetsLeft);
-                        final float right = (float) (rightInset + outsetsRight);
+                        final float left = (float) (adjustedLeftInset + outsetsLeft);
+                        final float right = (float) (adjustedRightInset + outsetsRight);
 
                         final float dstLeftX = dstX1 + left;
                         final float dstRightX = dstX2 - right;
                         final float srcLeftX = srcX1 + left;
                         final float srcRightX = srcX2 - right;
 
-                        // These assertions must hold, or rendering artifacts are highly likely to occur
-                        assert dstX1 != dstLeftX;
-                        assert dstLeftX != dstRightX;
-                        assert dstRightX != dstX2;
-
                         g.drawTexture3SliceH(cached,
                                              dstX1, dstY1, dstX2, dstY2,
                                              srcX1, srcY1, srcX2, srcY2,
                                              dstLeftX, dstRightX, srcLeftX, srcRightX);
                     } else if (sameWidth) {
                         // We do 3-patch rendering fixed width
-                        final float top = (float) (topInset + outsetsTop);
-                        final float bottom = (float) (bottomInset + outsetsBottom);
+                        final float top = (float) (adjustedTopInset + outsetsTop);
+                        final float bottom = (float) (adjustedBottomInset + outsetsBottom);
 
                         final float dstTopY = dstY1 + top;
                         final float dstBottomY = dstY2 - bottom;
                         final float srcTopY = srcY1 + top;
                         final float srcBottomY = srcY2 - bottom;
 
-                        // These assertions must hold, or rendering artifacts are highly likely to occur
-                        assert dstY1 != dstTopY;
-                        assert dstTopY != dstBottomY;
-                        assert dstBottomY != dstY2;
-
                         g.drawTexture3SliceV(cached,
                                              dstX1, dstY1, dstX2, dstY2,
                                              srcX1, srcY1, srcX2, srcY2,
                                              dstTopY, dstBottomY, srcTopY, srcBottomY);
                     } else {
                         // We do 9-patch rendering
-                        final float left = (float) (leftInset + outsetsLeft);
-                        final float top = (float) (topInset + outsetsTop);
-                        final float right = (float) (rightInset + outsetsRight);
-                        final float bottom = (float) (bottomInset + outsetsBottom);
+                        final float left = (float) (adjustedLeftInset + outsetsLeft);
+                        final float top = (float) (adjustedTopInset + outsetsTop);
+                        final float right = (float) (adjustedRightInset + outsetsRight);
+                        final float bottom = (float) (adjustedBottomInset + outsetsBottom);
 
                         final float dstLeftX = dstX1 + left;
                         final float dstRightX = dstX2 - right;
@@ -707,14 +715,6 @@
                         final float srcTopY = srcY1 + top;
                         final float srcBottomY = srcY2 - bottom;
 
-                        // These assertions must hold, or rendering artifacts are highly likely to occur
-                        assert dstY1 != dstTopY;
-                        assert dstTopY != dstBottomY;
-                        assert dstBottomY != dstY2;
-                        assert dstX1 != dstLeftX;
-                        assert dstLeftX != dstRightX;
-                        assert dstRightX != dstX2;
-
                         g.drawTexture9Slice(cached,
                                             dstX1, dstY1, dstX2, dstY2,
                                             srcX1, srcY1, srcX2, srcY2,
@@ -739,6 +739,8 @@
                     final int imgWidth = img.getWidth();
                     final int imgHeight = img.getHeight();
                     // TODO need to write tests which demonstrate this works when the image hasn't loaded yet. (RT-26978)
+                    // This doesn't work today. An NPE will occur, and then when the image does finally load,
+                    // we don't cause another pulse to occur so it doesn't ever get drawn.
                     // TODO need to write tests where we use a writable image and draw to it a lot. (RT-26978)
                     if (img != null && imgWidth != 0 && imgHeight != 0) {
                         final BackgroundSize size = image.getSize();
@@ -1167,6 +1169,9 @@
     }
 
     private void renderBackgroundShape(Graphics g) {
+        if (PulseLogger.PULSE_LOGGING_ENABLED) {
+            PulseLogger.PULSE_LOGGER.renderIncrementCounter("NGRegion renderBackgroundShape slow path");
+        }
         // We first need to draw each background fill. We don't pay any attention
         // to the radii of the BackgroundFill, but we do honor the insets and
         // the fill paint itself.
@@ -1215,6 +1220,9 @@
     }
 
     private void renderBackgrounds(Graphics g, float width, float height) {
+        if (PulseLogger.PULSE_LOGGING_ENABLED) {
+            PulseLogger.PULSE_LOGGER.renderIncrementCounter("NGRegion renderBackgrounds slow path");
+        }
         final List<BackgroundFill> fills = background.getFills();
         for (int i = 0, max = fills.size(); i < max; i++) {
             final BackgroundFill fill = fills.get(i);
--- a/modules/graphics/src/main/java/com/sun/javafx/sg/prism/NGShape3D.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/sg/prism/NGShape3D.java	Tue Sep 03 09:40:03 2013 -0700
@@ -184,11 +184,9 @@
 
     @Override
     protected void renderContent(Graphics g) {
-
         if (!Platform.isSupported(ConditionalFeature.SCENE3D) || material == null) {
             return;
         }
-
         renderMeshView(g);
     }
 
--- a/modules/graphics/src/main/java/com/sun/javafx/sg/prism/NodePath.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/sg/prism/NodePath.java	Tue Sep 03 09:40:03 2013 -0700
@@ -32,32 +32,33 @@
  * Simple a reusable storage for root-to-node path.
  *
  */
-public class NodePath<N extends NGNode> {
-    private List<N> path = new ArrayList<>();
+public class NodePath {
+    private List<NGNode> path = new ArrayList<>();
     private int position;
 
-    public NodePath() {
+    public NGNode last() {
+        return path.isEmpty() ? null : path.get(path.size() - 1);
     }
 
     // ITERATION methods
 
-    public N getCurrentNode() {
+    public NGNode getCurrentNode() {
         return path.get(position);
     }
 
     public boolean hasNext() {
-        return position > 0;
+        return position < path.size() -1 && !isEmpty();
     }
 
     public void next() {
         if (!hasNext()) {
             throw new IllegalStateException();
         }
-        position--;
+        position++;
     }
 
     public void reset() {
-        position = path.size() - 1;
+        position = path.isEmpty() ? -1 : 0;
     }
 
     // MODIFICATION methods
@@ -67,9 +68,9 @@
         path.clear();
     }
 
-    public void add(N n) {
-        path.add(n);
-        position = path.size() - 1;
+    public void add(NGNode n) {
+        path.add(0, n);
+        if (position == -1) position = 0;
     }
 
     public int size() {
@@ -77,7 +78,10 @@
     }
 
     public boolean isEmpty() {
-        return size() == 0;
+        return path.isEmpty();
     }
 
+    @Override public String toString() {
+        return path.toString();
+    }
 }
--- a/modules/graphics/src/main/java/com/sun/javafx/sg/prism/RegionImageCache.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/sg/prism/RegionImageCache.java	Tue Sep 03 09:40:03 2013 -0700
@@ -25,14 +25,11 @@
 
 package com.sun.javafx.sg.prism;
 
+import javafx.scene.layout.Background;
+import java.util.HashMap;
 import com.sun.javafx.geom.Rectangle;
 import com.sun.javafx.geom.Shape;
 import com.sun.javafx.logging.PulseLogger;
-
-import java.util.HashMap;
-
-import javafx.scene.layout.Background;
-
 import com.sun.prism.Graphics;
 import com.sun.prism.RTTexture;
 import com.sun.prism.ResourceFactory;
@@ -58,10 +55,8 @@
     private RectanglePacker vPacker;
 
 
-    RegionImageCache(Graphics g) {
+    RegionImageCache(final ResourceFactory factory) {
         imageMap = new HashMap<>();
-        ResourceFactory factory = g.getResourceFactory();
-
         backingStore = factory.createRTTexture(WIDTH + WIDTH, HEIGHT, WrapMode.CLAMP_NOT_NEEDED);
         backingStore.contentsUseful();
         backingStore.makePermanent();
--- a/modules/graphics/src/main/java/com/sun/javafx/text/GlyphLayout.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/text/GlyphLayout.java	Tue Sep 03 09:40:03 2013 -0700
@@ -176,9 +176,10 @@
         while (i < length) {
             char ch = chars[i];
             int codePoint = ch;
+            boolean delimiter = ch == '\t' || ch == '\n' || ch == '\r';
 
             /* special handling for delimiters */
-            if (ch == '\t' || ch == '\n' || ch == '\r') {
+            if (delimiter) {
                 if (i != start) {
                     run = addTextRun(layout, chars, start, i - start,
                                      font, span, bidiLevel, complex);
@@ -193,22 +194,11 @@
                 if (ch == '\r' && i < spanEnd && chars[i] == '\n') {
                     i++;
                 }
-
-                /* Create delimiter run */
-                run = new TextRun(start, i - start, bidiLevel, false,
-                                  ScriptMapper.COMMON, span, 0, false);
-                if (ch == '\t') {
-                    run.setTab();
-                    flags |= FLAGS_HAS_TABS;
-                } else {
-                    run.setLinebreak();
-                }
-                layout.addTextRun(run);
-                start = i;
-            } else {
-                boolean spanChanged = i >= spanEnd;
-                boolean levelChanged = i >= bidiEnd;
-                boolean scriptChanged = false;
+            }
+            boolean spanChanged = i >= spanEnd && i < length;
+            boolean levelChanged = i >= bidiEnd && i < length;
+            boolean scriptChanged = false;
+            if (!delimiter) {
                 boolean oldComplex = complex;
                 if (checkComplex) {
                     if (Character.isHighSurrogate(ch)) {
@@ -241,35 +231,47 @@
                        start = i;
                     }
                 }
-                if (spanChanged) {
-                    /* Only true for rich text (spans != null) */
-                    span = spans[++spanIndex];
-                    spanEnd += span.getText().length();
-                    font = (PGFont)span.getFont();
-                    if (font == null) {
-                        flags |= FLAGS_HAS_EMBEDDED;
-                    } else {
-                        FontResource fr = font.getFontResource();
-                        int requestedFeatures = font.getFeatures();
-                        int supportedFeatures = fr.getFeatures();
-                        feature = (requestedFeatures & supportedFeatures) != 0;
-                    }
+                i++;
+            }
+            if (spanChanged) {
+                /* Only true for rich text (spans != null) */
+                span = spans[++spanIndex];
+                spanEnd += span.getText().length();
+                font = (PGFont)span.getFont();
+                if (font == null) {
+                    flags |= FLAGS_HAS_EMBEDDED;
+                } else {
+                    FontResource fr = font.getFontResource();
+                    int requestedFeatures = font.getFeatures();
+                    int supportedFeatures = fr.getFeatures();
+                    feature = (requestedFeatures & supportedFeatures) != 0;
                 }
-                if (levelChanged) {
-                    bidiIndex++;
-                    /* Temporary Code: See RT-26997 */
-//                    bidiLevel = (byte)bidi.getRunLevel(bidiIndex);
-                    bidiLevel = (byte)bidi.getLevelAt(bidi.getRunStart(bidiIndex));
-                    bidiEnd = bidi.getRunLimit(bidiIndex);
-                    if ((bidiLevel & 1) != 0) {
-                        flags |= FLAGS_HAS_BIDI;
-                    }
+            }
+            if (levelChanged) {
+                bidiIndex++;
+                /* Temporary Code: See RT-26997 */
+//                bidiLevel = (byte)bidi.getRunLevel(bidiIndex);
+                bidiLevel = (byte)bidi.getLevelAt(bidi.getRunStart(bidiIndex));
+                bidiEnd = bidi.getRunLimit(bidiIndex);
+                if ((bidiLevel & 1) != 0) {
+                    flags |= FLAGS_HAS_BIDI;
                 }
-                if (scriptChanged) {
-                    scriptRun = script;
+            }
+            if (scriptChanged) {
+                scriptRun = script;
+            }
+            if (delimiter) {
+                /* Create delimiter run */
+                run = new TextRun(start, i - start, bidiLevel, false,
+                                  ScriptMapper.COMMON, span, 0, false);
+                if (ch == '\t') {
+                    run.setTab();
+                    flags |= FLAGS_HAS_TABS;
+                } else {
+                    run.setLinebreak();
                 }
-
-                i++;
+                layout.addTextRun(run);
+                start = i;
             }
         }
 
--- a/modules/graphics/src/main/java/com/sun/javafx/tk/TKDragGestureListener.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/tk/TKDragGestureListener.java	Tue Sep 03 09:40:03 2013 -0700
@@ -26,5 +26,7 @@
 package com.sun.javafx.tk;
 
 public interface TKDragGestureListener {
-    void dragGestureRecognized(double x, double y, double screenX, double screenY, int button);
+    void dragGestureRecognized(double x, double y,
+                               double screenX, double screenY,
+                               int button, TKClipboard dragboard);
 }
--- a/modules/graphics/src/main/java/com/sun/javafx/tk/TKDropTargetListener.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/tk/TKDropTargetListener.java	Tue Sep 03 09:40:03 2013 -0700
@@ -45,7 +45,7 @@
      * @return transfer mode chosen by potential target
      */
     public TransferMode dragEnter(double x, double y, double screenX, double screenY,
-                                  TransferMode transferMode);
+                                  TransferMode transferMode, TKClipboard dragboard);
 
     /**
      * Called during a drag gesture, while the mouse pointer is still
--- a/modules/graphics/src/main/java/com/sun/javafx/tk/quantum/GlassSceneDnDEventHandler.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/tk/quantum/GlassSceneDnDEventHandler.java	Tue Sep 03 09:40:03 2013 -0700
@@ -52,8 +52,9 @@
             @Override
             public TransferMode run() {
                 if (scene.dropTargetListener != null) {
+                    QuantumClipboard dragboard = QuantumClipboard.getDragboardInstance(dropTargetAssistant);
                     return scene.dropTargetListener.dragEnter(x, y, xAbs, yAbs,
-                            recommendedTransferMode);
+                            recommendedTransferMode, dragboard);
                 }
                 return null;
             }
@@ -108,15 +109,16 @@
     }
 
     public void handleDragStart(final int button, final int x, final int y, final int xAbs, final int yAbs,
-                                final ClipboardAssistance dropSourceAssistant)
+                                final ClipboardAssistance dragSourceAssistant)
     {
         assert Platform.isFxApplicationThread();
         AccessController.doPrivileged(new PrivilegedAction<Void>() {
             @Override
             public Void run() {
                 if (scene.dragGestureListener != null) {
+                    QuantumClipboard dragboard = QuantumClipboard.getDragboardInstance(dragSourceAssistant);
                     scene.dragGestureListener.dragGestureRecognized(
-                            x, y, xAbs, yAbs, button);
+                            x, y, xAbs, yAbs, button, dragboard);
                 }
                 return null;
             }
@@ -127,7 +129,7 @@
     // it's delivered by Glass itself.
     // Otherwise, see QuantumToolkit.createDragboard() and startDrag()
     public void handleDragEnd(final TransferMode performedTransferMode,
-                              final ClipboardAssistance dropSourceAssistant)
+                              final ClipboardAssistance dragSourceAssistant)
     {
         assert Platform.isFxApplicationThread();
         AccessController.doPrivileged(new PrivilegedAction<Void>() {
--- a/modules/graphics/src/main/java/com/sun/javafx/tk/quantum/GlassSystemMenu.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/tk/quantum/GlassSystemMenu.java	Tue Sep 03 09:40:03 2013 -0700
@@ -340,7 +340,7 @@
             assert PlatformUtil.isMac() || PlatformUtil.isLinux();
             int modifier = glassModifiers(kcc);
             if (PlatformUtil.isMac()) {
-                int finalCode = code.isLetterKey() ? code.impl_getChar().toLowerCase().charAt(0)
+                int finalCode = code.isLetterKey() ? code.impl_getChar().toUpperCase().charAt(0)
                         : code.impl_getCode();
                 glassSubMenuItem.setShortcut(finalCode, modifier);
             } else if (PlatformUtil.isLinux()) {
--- a/modules/graphics/src/main/java/com/sun/javafx/tk/quantum/UploadingPainter.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/tk/quantum/UploadingPainter.java	Tue Sep 03 09:40:03 2013 -0700
@@ -65,7 +65,6 @@
     @Override public void run() {
         renderLock.lock();
 
-        boolean locked = false;
         boolean valid = false;
         try {
             valid = validateStageGraphics();
@@ -76,13 +75,6 @@
                 }
                 return;
             }
-
-            /*
-             * As Glass is responsible for creating the rendering contexts,
-             * locking should be done prior to the Prism calls.
-             */
-            sceneState.lock();
-            locked = true;
             
             if (factory == null) {
                 factory = GraphicsPipeline.getDefaultResourceFactory();
@@ -163,9 +155,6 @@
             if (valid) {
                 Disposer.cleanUp();
             }
-            if (locked) {
-                sceneState.unlock();
-            }
 
             sceneState.getScene().setPainting(false);
             if (PrismSettings.poolStats ||
--- a/modules/graphics/src/main/java/com/sun/javafx/tk/quantum/ViewPainter.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/tk/quantum/ViewPainter.java	Tue Sep 03 09:40:03 2013 -0700
@@ -25,35 +25,46 @@
 
 package com.sun.javafx.tk.quantum;
 
-import java.util.Set;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.locks.ReentrantLock;
 import com.sun.javafx.geom.DirtyRegionContainer;
 import com.sun.javafx.geom.DirtyRegionPool;
 import com.sun.javafx.geom.RectBounds;
 import com.sun.javafx.geom.Rectangle;
 import com.sun.javafx.geom.transform.Affine3D;
+import com.sun.javafx.geom.transform.BaseTransform;
 import com.sun.javafx.geom.transform.GeneralTransform3D;
-import com.sun.javafx.jmx.HighlightRegion;
-import com.sun.javafx.runtime.SystemProperties;
 import com.sun.javafx.sg.prism.NGCamera;
+import com.sun.javafx.sg.prism.NGNode;
 import com.sun.javafx.sg.prism.NGPerspectiveCamera;
 import com.sun.javafx.sg.prism.NodePath;
-import com.sun.javafx.sg.prism.NGNode;
-import com.sun.javafx.tk.Toolkit;
-import com.sun.prism.BasicStroke;
 import com.sun.prism.Graphics;
 import com.sun.prism.GraphicsResource;
+import com.sun.prism.Image;
 import com.sun.prism.Presentable;
+import com.sun.prism.RTTexture;
 import com.sun.prism.ResourceFactory;
+import com.sun.prism.Texture;
 import com.sun.prism.impl.PrismSettings;
 import com.sun.prism.paint.Color;
 import com.sun.prism.paint.Paint;
+import static com.sun.javafx.logging.PulseLogger.PULSE_LOGGER;
+import static com.sun.javafx.logging.PulseLogger.PULSE_LOGGING_ENABLED;
 
-import static com.sun.javafx.logging.PulseLogger.PULSE_LOGGING_ENABLED;
-import static com.sun.javafx.logging.PulseLogger.PULSE_LOGGER;
-
+/**
+ * Responsible for "painting" a scene. It invokes as appropriate API on the root NGNode
+ * of a scene to determine dirty regions, render roots, etc. Also calls the render root
+ * to render. Also invokes code to print dirty opts and paint overdraw rectangles according
+ * to debug flags.
+ */
 abstract class ViewPainter implements Runnable {
-    private static NodePath<NGNode>[] ROOT_PATHS = new NodePath[PrismSettings.dirtyRegionCount];
+    /**
+     * An array of initially empty ROOT_PATHS. They are created on demand as
+     * needed. Each path is associated with a different dirty region. We have
+     * up to PrismSettings.dirtyRegionCount max dirty regions
+     */
+    private static NodePath[] ROOT_PATHS = new NodePath[PrismSettings.dirtyRegionCount];
 
     /*
      * This could be a per-scene lock but there is no guarantee that the
@@ -79,6 +90,15 @@
 
     private boolean renderOverlay = false;
 
+    /**
+     * root is the root node of the scene. overlayRoot is the root node of any
+     * overlay which may be present (such as used for full screen overlay).
+     */
+    private NGNode root, overlayRoot;
+
+    // These variables are all used as part of the dirty region optimizations,
+    // and if dirty opts are turned off via a runtime flag, then these fields
+    // are never initialized or used.
     private Rectangle dirtyRect;
     private RectBounds clip;
     private RectBounds dirtyRegionTemp;
@@ -88,13 +108,28 @@
     private Affine3D scaleTx;
     private GeneralTransform3D viewProjTx;
     private GeneralTransform3D projTx;
-    private NGNode root, overlayRoot;
+
+    /**
+     * This is used for drawing dirty regions and overdraw rectangles in cases where we are
+     * not drawing the entire scene every time (specifically, when depth buffer is disabled).
+     * In those cases we will draw the scene to the sceneBuffer, clear the actual back buffer,
+     * blit the sceneBuffer into the back buffer, and then scribble on top of the back buffer
+     * with the dirty regions and/or overdraw rectangles.
+     *
+     * When the depthBuffer is enabled on a scene, we always end up drawing the entire scene
+     * anyway, so we don't bother with this sceneBuffer in that case. Of course, if dirty
+     * region / overdraw rectangle drawing is turned off, then we don't use this. Thus,
+     * only when you are doing some kind of debugging would this field be used and the
+     * extra buffer copy incurred.
+     */
+    private RTTexture sceneBuffer;
 
     protected ViewPainter(GlassScene gs) {
         sceneState = gs.getSceneState();
         if (sceneState == null) {
             throw new NullPointerException("Scene state is null");
         }
+
         if (PrismSettings.dirtyOptsEnabled) {
             tx = new Affine3D();
             viewProjTx = new GeneralTransform3D();
@@ -108,81 +143,176 @@
         }
     }
 
-    protected void setRoot(NGNode node) {
+    protected final void setRoot(NGNode node) {
         root = node;
     }
 
-    protected void setOverlayRoot(NGNode node) {
+    protected final void setOverlayRoot(NGNode node) {
         overlayRoot = node;
     }
 
-    protected void setRenderOverlay(boolean val) {
+    protected final void setRenderOverlay(boolean val) {
         renderOverlay = val;
     }
 
     private void adjustPerspective(NGCamera camera) {
+        // This should definitely be true since this is only called by setDirtyRect
+        assert PrismSettings.dirtyOptsEnabled;
         if (camera instanceof NGPerspectiveCamera) {
-            NGPerspectiveCamera perspCamera = (NGPerspectiveCamera) camera;
             scaleTx.setToScale(width / 2.0, -height / 2.0, 1);
             scaleTx.translate(1, -1);
             projTx.mul(scaleTx);
-            viewProjTx = perspCamera.getProjViewTx(viewProjTx);
+            viewProjTx = camera.getProjViewTx(viewProjTx);
             projTx.mul(viewProjTx);
         }
     }
 
-    private int setDirtyRect() {
-        clip.setBounds(0, 0, width, height);
-        dirtyRegionTemp.makeEmpty();
-        dirtyRegionContainer.reset();
-        tx.setToIdentity();
-        projTx.setIdentity();
-        adjustPerspective(sceneState.getScene().getCamera());
-        int status = root.accumulateDirtyRegions(clip, dirtyRegionTemp,
-                                                 dirtyRegionPool, dirtyRegionContainer,
-                                                 tx, projTx);
-        dirtyRegionContainer.roundOut();
+    protected void paintImpl(final Graphics backBufferGraphics) {
+        // We should not be painting anything with a width / height
+        // that is <= 0, so we might as well bail right off.
+        if (width <= 0 || height <= 0) return;
 
-        return status;
-    }
+        // This "g" variable might represent the back buffer graphics, or it
+        // might be reassigned to the sceneBuffer graphics.
+        Graphics g = backBufferGraphics;
+        // Take into account the pixel scale factor for retina displays
+        final float pixelScale = presentable == null ? 1.0f : presentable.getPixelScaleFactor();
+        // Initialize renderEverything based on various conditions that will cause us to render
+        // the entire scene every time.
+        // TODO is calling isEntireSceneDirty on the GlassScene safe from this thread?
+        boolean renderEverything = renderOverlay ||
+                sceneState.getScene().isEntireSceneDirty() ||
+                sceneState.getScene().getDepthBuffer() ||
+                !PrismSettings.dirtyOptsEnabled;
+        // We are going to draw dirty opt boxes either if we're supposed to show the dirty
+        // regions, or if we're supposed to show the overdraw boxes.
+        final boolean showDirtyOpts = PrismSettings.showDirtyRegions || PrismSettings.showOverdraw;
+        // If showDirtyOpts is turned on and we're not using a depth buffer
+        // then we will render the scene to an intermediate texture, and then at the end we'll
+        // draw that intermediate texture to the back buffer.
+        if (showDirtyOpts && !sceneState.getScene().getDepthBuffer()) {
+            final int bufferWidth = (int) Math.ceil(width * pixelScale);
+            final int bufferHeight = (int) Math.ceil(height * pixelScale);
+            // Check whether the sceneBuffer texture needs to be reconstructed
+            if (sceneBuffer != null) {
+                sceneBuffer.lock();
+                if (sceneBuffer.isSurfaceLost() ||
+                        bufferWidth != sceneBuffer.getContentWidth() ||
+                        bufferHeight != sceneBuffer.getContentHeight()) {
+                    sceneBuffer.unlock();
+                    sceneBuffer.dispose();
+                    sceneBuffer = null;
+                }
+            }
+            // If sceneBuffer is null, we need to create a new texture. In this
+            // case we will also need to render the whole scene (so don't bother
+            // with dirty opts)
+            if (sceneBuffer == null) {
+                sceneBuffer = g.getResourceFactory().createRTTexture(
+                        bufferWidth,
+                        bufferHeight,
+                        Texture.WrapMode.CLAMP_TO_ZERO,
+                        false);
+                renderEverything = true;
+            }
+            sceneBuffer.contentsUseful();
+            // Hijack the "g" graphics variable
+            g = sceneBuffer.createGraphics();
+            g.scale(pixelScale, pixelScale);
+        } else if (sceneBuffer != null) {
+            // We're in a situation where we have previously rendered to the sceneBuffer, but in
+            // this render pass for whatever reason we're going to draw directly to the back buffer.
+            // In this case we need to release the sceneBuffer.
+            sceneBuffer.dispose();
+            sceneBuffer = null;
+        }
 
-    protected void paintImpl(Graphics g) {
-        int status = DirtyRegionContainer.DTR_CONTAINS_CLIP;
-        if (PrismSettings.dirtyOptsEnabled) {
+        // The status will be set only if we're rendering with dirty regions
+        int status = -1;
+
+        // If we're rendering with dirty regions, then we'll call the root node to accumulate
+        // the dirty regions and then again to do the pre culling.
+        if (!renderEverything) {
             long start = PULSE_LOGGING_ENABLED ? System.currentTimeMillis() : 0;
-            if (!sceneState.getScene().isEntireSceneDirty() && !renderOverlay) {
-                status = setDirtyRect();
-                if (status == DirtyRegionContainer.DTR_OK) {
-                    root.doPreCulling(dirtyRegionContainer,
-                                      tx, projTx);
-                }
+            clip.setBounds(0, 0, width, height);
+            dirtyRegionTemp.makeEmpty();
+            dirtyRegionContainer.reset();
+            tx.setToIdentity();
+            projTx.setIdentity();
+            adjustPerspective(sceneState.getScene().getCamera());
+            status = root.accumulateDirtyRegions(clip, dirtyRegionTemp,
+                                                     dirtyRegionPool, dirtyRegionContainer,
+                                                     tx, projTx);
+            dirtyRegionContainer.roundOut();
+            if (status == DirtyRegionContainer.DTR_OK) {
+                root.doPreCulling(dirtyRegionContainer, tx, projTx);
             }
             if (PULSE_LOGGING_ENABLED) {
                 PULSE_LOGGER.renderMessage(start, System.currentTimeMillis(), "Dirty Opts Computed");
             }
         }
 
-        if (!PrismSettings.showDirtyRegions && status == DirtyRegionContainer.DTR_OK) {
-            final int dirtyRegionSize = dirtyRegionContainer.size();
+        // We're going to need to iterate over the dirty region container a lot, so we
+        // might as well save this reference.
+        final int dirtyRegionSize = status == DirtyRegionContainer.DTR_OK ? dirtyRegionContainer.size() : 0;
+
+        if (dirtyRegionSize > 0) {
+            // We set this flag on Graphics so that subsequent code in the render paths of
+            // NGNode know whether they ought to be paying attention to dirty region
+            // culling bits.
             g.setHasPreCullingBits(true);
-            if (PULSE_LOGGING_ENABLED && dirtyRegionSize > 1) {
+
+            // Find the render roots. There is a different render root for each dirty region
+            long start = PULSE_LOGGING_ENABLED ? System.currentTimeMillis() : 0;
+            for (int i = 0; i < dirtyRegionSize; ++i) {
+                NodePath path = getRootPath(i);
+                path.clear();
+                root.getRenderRoot(getRootPath(i), dirtyRegionContainer.getDirtyRegion(i), i, tx, projTx);
+            }
+            if (PULSE_LOGGING_ENABLED) {
+                PULSE_LOGGER.renderMessage(start, System.currentTimeMillis(), "Render Roots Discovered");
+            }
+
+            // For debug purposes, write out to the pulse logger the number and size of the dirty
+            // regions that are being used to render this pulse.
+            if (PULSE_LOGGING_ENABLED) {
                 PULSE_LOGGER.renderMessage(dirtyRegionSize + " different dirty regions to render");
-            }
-            float pixelScale = (presentable == null ? 1.0f : presentable.getPixelScaleFactor());
-            if (!sceneState.getScene().getDepthBuffer() && PrismSettings.occlusionCullingEnabled) {
-                for (int i = 0; i < dirtyRegionSize; ++i) {
-                    root.getRenderRoot(getRootPath(i), dirtyRegionContainer.getDirtyRegion(i), i, tx, projTx);
+                for (int i=0; i<dirtyRegionSize; i++) {
+                    PULSE_LOGGER.renderMessage("Dirty Region " + i + ": " + dirtyRegionContainer.getDirtyRegion(i));
+                    PULSE_LOGGER.renderMessage("Render Root Path " + i + ": " + getRootPath(i));
                 }
             }
+
+            // If -Dprism.printrendergraph=true then we want to print out the render graph to the
+            // pulse logger, annotated with all the dirty opts. Invisible nodes are skipped.
+            if (PULSE_LOGGING_ENABLED && PrismSettings.printRenderGraph) {
+                StringBuilder s = new StringBuilder();
+                List<NGNode> roots = new ArrayList<>();
+                for (int i = 0; i < dirtyRegionSize; i++) {
+                    final RectBounds dirtyRegion = dirtyRegionContainer.getDirtyRegion(i);
+                    // TODO it should be impossible to have ever created a dirty region that was empty...
+                    if (dirtyRegion.getWidth() > 0 && dirtyRegion.getHeight() > 0) {
+                        NodePath nodePath = getRootPath(i);
+                        if (!nodePath.isEmpty()) {
+                            roots.add(nodePath.last());
+                        }
+                    }
+                }
+                root.printDirtyOpts(s, roots);
+                PULSE_LOGGER.renderMessage(s.toString());
+            }
+
+            // Paint each dirty region
             for (int i = 0; i < dirtyRegionSize; ++i) {
                 final RectBounds dirtyRegion = dirtyRegionContainer.getDirtyRegion(i);
-                // make sure we are not trying to render in some invalid region
+                // TODO it should be impossible to have ever created a dirty region that was empty...
+                // Make sure we are not trying to render in some invalid region
                 if (dirtyRegion.getWidth() > 0 && dirtyRegion.getHeight() > 0) {
-                    // set the clip rectangle using integer
-                    // bounds since a fractional bounding box will
-                    // still require a complete repaint on
-                    // pixel boundaries
+                    // Set the clip rectangle using integer bounds since a fractional bounding box will
+                    // still require a complete repaint on pixel boundaries
                     dirtyRect.setBounds(dirtyRegion);
+                    // TODO I don't understand why this is needed. And if it is, are fractional pixelScale
+                    // values OK? And if not, shouldn't pixelScale be an int instead?
                     if (pixelScale != 1.0f) {
                         dirtyRect.x *= pixelScale;
                         dirtyRect.y *= pixelScale;
@@ -191,81 +321,98 @@
                     }
                     g.setClipRect(dirtyRect);
                     g.setClipRectIndex(i);
-
-                    // Disable occlusion culling if depth buffer is enabled for the scene.
-                    if (sceneState.getScene().getDepthBuffer() || !PrismSettings.occlusionCullingEnabled) {
-                        doPaint(g, null);
-                    } else {
-                        final NodePath<NGNode> path = getRootPath(i);
-                        doPaint(g, path);
-                        path.clear();
-                    }
+                    doPaint(g, getRootPath(i));
                 }
             }
         } else {
+            // There are no dirty regions, so just paint everything
             g.setHasPreCullingBits(false);
             g.setClipRect(null);
             this.doPaint(g, null);
         }
 
-        if (PrismSettings.showDirtyRegions) {
-            if (PrismSettings.showCull) {
-                 root.drawCullBits(g);
-            }
-
-            // save current depth test state
-            boolean prevDepthTest = g.isDepthTest();
-
-            g.setDepthTest(false);
-            if (status == DirtyRegionContainer.DTR_OK) {
-                g.setPaint(new Color(1, 0, 0, .3f));
-                for (int i = 0; i < dirtyRegionContainer.size(); i++) {
-                    RectBounds reg = dirtyRegionContainer.getDirtyRegion(i);
-                    g.fillRect(reg.getMinX(), reg.getMinY(),
-                               reg.getWidth(), reg.getHeight());
-                }
-            } else {
-                g.setPaint(new Color(1, 0, 0, .3f));
-                g.fillRect(0, 0, width, height);
-            }
-
-            // restore previous depth test state
-            g.setDepthTest(prevDepthTest);
-
-        }
-
-        if (SystemProperties.isDebug()) {
-            Set<HighlightRegion> highlightRegions =
-                    Toolkit.getToolkit().getHighlightedRegions();
-            if (highlightRegions != null) {
-                g.setStroke(new BasicStroke(1f,
-                                            BasicStroke.CAP_BUTT,
-                                            BasicStroke.JOIN_BEVEL,
-                                            10f));
-                for (HighlightRegion region: highlightRegions) {
-                    if (sceneState.getScene().equals(region.getTKScene())) {
-                        g.setPaint(new Color(1, 1, 1, 1));
-                        g.drawRect((float) region.getMinX(),
-                                   (float) region.getMinY(),
-                                   (float) region.getWidth(),
-                                   (float) region.getHeight());
-                        g.setPaint(new Color(0, 0, 0, 1));
-                        g.drawRect((float) region.getMinX() - 1,
-                                   (float) region.getMinY() - 1,
-                                   (float) region.getWidth() + 2,
-                                   (float) region.getHeight() + 2);
-                    }
-                }
-            }
-        }
+        // If we have an overlay then we need to render it too.
         if (renderOverlay) {
             overlayRoot.render(g);
         }
+
+        // If we're showing dirty regions or overdraw, then we're going to need to draw
+        // over-top the normal scene. If we have been drawing do the back buffer, then we
+        // will just draw on top of it. If we have been drawing to the sceneBuffer, then
+        // we will first blit the sceneBuffer into the back buffer, and then draw directly
+        // on the back buffer.
+        if (showDirtyOpts) {
+            if (sceneBuffer != null) {
+                g.sync();
+                backBufferGraphics.clear();
+                backBufferGraphics.drawTexture(sceneBuffer, 0, 0, width, height,
+                        sceneBuffer.getContentX(), sceneBuffer.getContentY(),
+                        sceneBuffer.getContentX() + sceneBuffer.getContentWidth(),
+                        sceneBuffer.getContentY() + sceneBuffer.getContentHeight());
+                sceneBuffer.unlock();
+            }
+
+            if (PrismSettings.showOverdraw) {
+                // We are going to show the overdraw rectangles.
+                if (dirtyRegionSize > 0) {
+                    // In this case we have dirty regions, so we will iterate over them all
+                    // and draw each dirty region's overdraw individually
+                    for (int i = 0; i < dirtyRegionSize; i++) {
+                        final Rectangle clip = new Rectangle(dirtyRegionContainer.getDirtyRegion(i));
+                        backBufferGraphics.setClipRectIndex(i);
+                        paintOverdraw(backBufferGraphics, clip);
+                        backBufferGraphics.setPaint(new Color(1, 0, 0, .3f));
+                        backBufferGraphics.drawRect(clip.x, clip.y, clip.width, clip.height);
+                    }
+                } else {
+                    // In this case there were no dirty regions, so the clip is the entire scene
+                    final Rectangle clip = new Rectangle(0, 0, width, height);
+                    assert backBufferGraphics.getClipRectIndex() == 0;
+                    paintOverdraw(backBufferGraphics, clip);
+                    backBufferGraphics.setPaint(new Color(1, 0, 0, .3f));
+                    backBufferGraphics.drawRect(clip.x, clip.y, clip.width, clip.height);
+                }
+            } else {
+                // We are going to show the dirty regions
+                if (dirtyRegionSize > 0) {
+                    // We have dirty regions to draw
+                    backBufferGraphics.setPaint(new Color(1, 0, 0, .3f));
+                    for (int i = 0; i < dirtyRegionSize; i++) {
+                        final RectBounds reg = dirtyRegionContainer.getDirtyRegion(i);
+                        backBufferGraphics.fillRect(reg.getMinX(), reg.getMinY(), reg.getWidth(), reg.getHeight());
+                    }
+                } else {
+                    // No dirty regions, fill the entire view area
+                    backBufferGraphics.setPaint(new Color(1, 0, 0, .3f));
+                    backBufferGraphics.fillRect(0, 0, width, height);
+                }
+            }
+            root.clearPainted();
+        }
     }
 
-    private static NodePath<NGNode> getRootPath(int i) {
+    /**
+     * Utility method for painting the overdraw rectangles. Right now we're using a computationally
+     * intensive approach of having an array of integers (image data) that we then write to in the
+     * NGNodes, recording how many times each pixel position has been touched (well, technically, we're
+     * just recording the bounds of drawn objects, so some pixels might be "red" but actually were never
+     * drawn).
+     *
+     * @param g
+     * @param clip
+     */
+    private void paintOverdraw(final Graphics g, final Rectangle clip) {
+        final int[] pixels = new int[clip.width * clip.height];
+        root.drawDirtyOpts(BaseTransform.IDENTITY_TRANSFORM, projTx, clip, pixels, g.getClipRectIndex());
+        final Image image = Image.fromIntArgbPreData(pixels, clip.width, clip.height);
+        final Texture texture = factory.getCachedTexture(image, Texture.WrapMode.CLAMP_TO_EDGE);
+        g.drawTexture(texture, clip.x, clip.y, clip.x+clip.width, clip.y+clip.height, 0, 0, clip.width, clip.height);
+        texture.unlock();
+    }
+
+    private static NodePath getRootPath(int i) {
         if (ROOT_PATHS[i] == null) {
-            ROOT_PATHS[i] = new NodePath<>();
+            ROOT_PATHS[i] = new NodePath();
         }
         return ROOT_PATHS[i];
     }
@@ -290,10 +437,7 @@
         return sceneState.isWindowVisible() && !sceneState.isWindowMinimized();
     }
 
-    private void doPaint(Graphics g, NodePath<NGNode> renderRootPath) {
-        if (PrismSettings.showDirtyRegions) {
-            g.setClipRect(null);
-        }
+    private void doPaint(Graphics g, NodePath renderRootPath) {
         // Null path indicates that occlusion culling is not used
         if (renderRootPath != null) {
             if (renderRootPath.isEmpty()) {
@@ -332,5 +476,4 @@
             }
         }
     }
-
 }
--- a/modules/graphics/src/main/java/com/sun/javafx/tk/quantum/ViewScene.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/tk/quantum/ViewScene.java	Tue Sep 03 09:40:03 2013 -0700
@@ -34,6 +34,9 @@
 import com.sun.javafx.cursor.CursorFrame;
 import com.sun.javafx.sg.prism.NGNode;
 import com.sun.javafx.tk.Toolkit;
+import com.sun.prism.GraphicsPipeline;
+import com.sun.prism.j2d.J2DPipeline;
+import com.sun.prism.sw.SWPipeline;
 
 class ViewScene extends GlassScene {
 
@@ -69,7 +72,7 @@
         super.setStage(stage);
         if (stage != null) {
             WindowStage wstage  = (WindowStage)stage;
-            if (wstage.needsUpdateWindow()) {
+            if (wstage.needsUpdateWindow() || GraphicsPipeline.getPipeline().isUploading()) {
                 if (Pixels.getNativeFormat() != Pixels.Format.BYTE_BGRA_PRE ||
                     ByteOrder.nativeOrder() != ByteOrder.LITTLE_ENDIAN) {
                     throw new UnsupportedOperationException(UNSUPPORTED_FORMAT);
--- a/modules/graphics/src/main/java/com/sun/prism/Graphics.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/Graphics.java	Tue Sep 03 09:40:03 2013 -0700
@@ -34,6 +34,7 @@
 import com.sun.javafx.scene.text.GlyphList;
 import com.sun.javafx.sg.prism.NGCamera;
 import com.sun.javafx.sg.prism.NGLightBase;
+import com.sun.javafx.sg.prism.NodePath;
 import com.sun.prism.paint.Color;
 import com.sun.prism.paint.Paint;
 
@@ -196,8 +197,8 @@
     public ResourceFactory getResourceFactory();
     public RenderTarget getRenderTarget();
 
-    public void setRenderRoot(Object root);
-    public Object getRenderRoot();
+    public void setRenderRoot(NodePath root);
+    public NodePath getRenderRoot();
 
     public void setState3D(boolean flag);
     public boolean isState3D();
--- a/modules/graphics/src/main/java/com/sun/prism/GraphicsPipeline.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/GraphicsPipeline.java	Tue Sep 03 09:40:03 2013 -0700
@@ -222,4 +222,12 @@
     public boolean isEffectSupported() {
         return true;
     }
+
+    /**
+     * Checks if the GraphicsPipeline uses uploading or presenting painter
+     * @return true if the pipeline uses an uploading painter
+     */
+    public boolean isUploading() {
+        return false;
+    }
 }
--- a/modules/graphics/src/main/java/com/sun/prism/es2/EGLFBGLDrawable.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/es2/EGLFBGLDrawable.java	Tue Sep 03 09:40:03 2013 -0700
@@ -62,9 +62,14 @@
     @Override
     boolean swapBuffers(GLContext glCtx) {
         boolean retval = nSwapBuffers(getNativeDrawableInfo());
+        // TODO: This looks hacky. Need to find a better approach.
+        // For eglfb, we are painting in Z-order from the back,
+        // possibly (likely) with an app that does not cover the
+        // full screen. We need to start each paint with an empty canvas.
+        // The assumption here was that we would do that by clearing the buffer. 
         glCtx.clearBuffers(
                 transparentFramebuffer ? Color.TRANSPARENT : Color.BLACK,
-                true, true, false);
+                true, true, true);
         return retval;
     }
 }
--- a/modules/graphics/src/main/java/com/sun/prism/es2/GLContext.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/es2/GLContext.java	Tue Sep 03 09:40:03 2013 -0700
@@ -25,15 +25,15 @@
 
 package com.sun.prism.es2;
 
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
 import com.sun.javafx.PlatformUtil;
 import com.sun.prism.MeshView;
 import com.sun.prism.PhongMaterial.MapType;
 import com.sun.prism.Texture.WrapMode;
 import com.sun.prism.impl.PrismSettings;
 import com.sun.prism.paint.Color;
-import java.nio.Buffer;
-import java.nio.ByteBuffer;
-import java.nio.IntBuffer;
 
 abstract class GLContext {
 
@@ -108,6 +108,7 @@
     // track some other state here to avoid redundant state changes
     private int activeTexUnit;
     private int[] boundTextures = new int[4];
+    private int viewportX, viewportY, viewportWidth, viewportHeight;
     // depthTest is initialized to false in the native initState method
     private boolean depthTest = false;
     private boolean msaa = false;
@@ -334,6 +335,9 @@
      * @return FBO id
      */
     int createFBO(int texID) {
+        if (nativeFBOID != FBO_ID_NOCACHE) {
+            nativeFBOID = FBO_ID_UNSET; // invalidate FBO ID cache
+        } 
         return nCreateFBO(nativeCtxInfo, texID);
     }
 
@@ -585,7 +589,13 @@
 
     void updateViewportAndDepthTest(int x, int y, int w, int h,
             boolean depthTest) {
-        nUpdateViewport(nativeCtxInfo, x, y, w, h);
+        if (viewportX != x || viewportY != y || viewportWidth != w || viewportHeight != h) {
+            viewportX = x;
+            viewportY = y;
+            viewportWidth = w;
+            viewportHeight = h;
+            nUpdateViewport(nativeCtxInfo, x, y, w, h);
+        }
         if (this.depthTest != depthTest) {
             nSetDepthTest(nativeCtxInfo, depthTest);
             this.depthTest = depthTest;
--- a/modules/graphics/src/main/java/com/sun/prism/impl/BaseGraphics.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/impl/BaseGraphics.java	Tue Sep 03 09:40:03 2013 -0700
@@ -35,6 +35,7 @@
 import com.sun.javafx.geom.transform.Affine3D;
 import com.sun.javafx.geom.transform.BaseTransform;
 import com.sun.javafx.sg.prism.NGCamera;
+import com.sun.javafx.sg.prism.NodePath;
 import com.sun.prism.BasicStroke;
 import com.sun.prism.CompositeMode;
 import com.sun.prism.PixelFormat;
@@ -209,14 +210,14 @@
         return hasPreCullingBits;
     }
 
-    private Object renderRoot;
+    private NodePath renderRoot;
     @Override
-    public final void setRenderRoot(Object root) {
+    public final void setRenderRoot(NodePath root) {
         this.renderRoot = root;
     }
 
     @Override
-    public final Object getRenderRoot() {
+    public final NodePath getRenderRoot() {
         return renderRoot;
     }
 
--- a/modules/graphics/src/main/java/com/sun/prism/impl/GlyphCache.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/impl/GlyphCache.java	Tue Sep 03 09:40:03 2013 -0700
@@ -59,8 +59,8 @@
     // 2048 pixels introduced very noticeable pauses when trying
     // to free 1/4 of the glyphs, which for spiral text also amounts
     // to 1/4 of the strikes.
-    private static final int WIDTH = 1024; // in pixels
-    private static final int HEIGHT = 1024; // in pixels
+    private static final int WIDTH = PrismSettings.glyphCacheWidth; // in pixels
+    private static final int HEIGHT = PrismSettings.glyphCacheHeight; // in pixels
     private static ByteBuffer emptyMask;
 
     private final BaseContext context;
--- a/modules/graphics/src/main/java/com/sun/prism/impl/PrismSettings.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/impl/PrismSettings.java	Tue Sep 03 09:40:03 2013 -0700
@@ -60,7 +60,8 @@
     public static final boolean forceRepaint;
     public static final boolean noFallback;
     public static final boolean showDirtyRegions;
-    public static final boolean showCull;
+    public static final boolean showOverdraw;
+    public static final boolean printRenderGraph;
     public static final boolean shutdownHook;
     public static final int minTextureSize;
     public static final int minRTTSize;
@@ -79,6 +80,8 @@
     public static final boolean poolStats;
     public static final boolean poolDebug;
     public static final boolean disableEffects;
+    public static final int glyphCacheWidth;
+    public static final int glyphCacheHeight;
 
     private PrismSettings() {
     }
@@ -117,25 +120,30 @@
                                                "prism.occlusion.culling",
                                                true);
 
-        dirtyRegionCount = getInt(systemProperties, "prism.dirtyregioncount",
-                                  6, null);
+        // The maximum number of dirty regions to use. The absolute max that we can
+        // support at present is 15.
+        dirtyRegionCount = Math.max(getInt(systemProperties, "prism.dirtyregioncount",
+                                  6, null), 15);
 
         /* Dirty region optimizations */
         threadCheck = getBoolean(systemProperties, "prism.threadcheck", false);
 
-        /* Force scene repaint on every frame */
-        showDirtyRegions = getBoolean(systemProperties, "prism.showdirty",
-                                      false);
+        /* Draws overlay rectangles showing where the dirty regions were */
+        showDirtyRegions = getBoolean(systemProperties, "prism.showdirty", false);
 
-        /* marks all nodes with color green=render gray=culloff */
-        showCull = getBoolean(systemProperties, "prism.showcull",
-                              false);
+        /*
+         * Draws overlay rectangles showing not only the dirty regions, but how many times
+         * each area within that dirty region was drawn (covered by bounds of a drawn object).
+         */
+        showOverdraw = getBoolean(systemProperties, "prism.showoverdraw", false);
+
+        /* Prints out the render graph, annotated with dirty opts information */
+        printRenderGraph = getBoolean(systemProperties, "prism.printrendergraph", false);
 
         /* Force scene repaint on every frame */
-        forceRepaint = getBoolean(systemProperties, "prism.forcerepaint",
-                                  false);
+        forceRepaint = getBoolean(systemProperties, "prism.forcerepaint", false);
 
-        /* disable fallback to another toolkit if prism coudln't be init-ed */
+        /* disable fallback to another toolkit if prism couldn't be init-ed */
         noFallback = getBoolean(systemProperties, "prism.noFallback", false);
 
         /* Shape caching optimizations */
@@ -320,6 +328,11 @@
         disableD3D9Ex = getBoolean(systemProperties, "prism.disableD3D9Ex", true);
         
         disableEffects = getBoolean(systemProperties, "prism.disableEffects", false);
+
+        glyphCacheWidth = getInt(systemProperties, "prism.glyphCacheWidth", 1024,
+                "Try -Dprism.glyphCacheWidth=<number>");
+        glyphCacheHeight = getInt(systemProperties, "prism.glyphCacheHeight", 1024,
+                "Try -Dprism.glyphCacheHeight=<number>");
     }
 
     private static int parseInt(String s, int dflt, int trueDflt,
--- a/modules/graphics/src/main/java/com/sun/prism/j2d/J2DPipeline.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/j2d/J2DPipeline.java	Tue Sep 03 09:40:03 2013 -0700
@@ -111,4 +111,9 @@
         }
         return j2DFontFactory;
     }
+
+    @Override
+    public boolean isUploading() {
+        return true;
+    }
 }
--- a/modules/graphics/src/main/java/com/sun/prism/j2d/J2DPrismGraphics.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/j2d/J2DPrismGraphics.java	Tue Sep 03 09:40:03 2013 -0700
@@ -48,6 +48,7 @@
 import com.sun.javafx.scene.text.GlyphList;
 import com.sun.javafx.sg.prism.NGCamera;
 import com.sun.javafx.sg.prism.NGLightBase;
+import com.sun.javafx.sg.prism.NodePath;
 import com.sun.prism.BasicStroke;
 import com.sun.prism.CompositeMode;
 import com.sun.prism.MaskTextureGraphics;
@@ -1326,14 +1327,14 @@
         return hasPreCullingBits;
     }
 
-    private Object renderRoot;
+    private NodePath renderRoot;
     @Override
-    public void setRenderRoot(Object root) {
+    public void setRenderRoot(NodePath root) {
         this.renderRoot = root;
     }
 
     @Override
-    public Object getRenderRoot() {
+    public NodePath getRenderRoot() {
         return renderRoot;
     }
 
--- a/modules/graphics/src/main/java/com/sun/prism/sw/SWGraphics.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/sw/SWGraphics.java	Tue Sep 03 09:40:03 2013 -0700
@@ -44,6 +44,7 @@
 import com.sun.javafx.scene.text.GlyphList;
 import com.sun.javafx.sg.prism.NGCamera;
 import com.sun.javafx.sg.prism.NGLightBase;
+import com.sun.javafx.sg.prism.NodePath;
 import com.sun.pisces.GradientColorMap;
 import com.sun.pisces.PiscesRenderer;
 import com.sun.pisces.RendererBase;
@@ -96,14 +97,14 @@
 
     private boolean hasPreCullingBits = false;
 
-    private Object renderRoot;
+    private NodePath renderRoot;
     @Override
-    public void setRenderRoot(Object root) {
+    public void setRenderRoot(NodePath root) {
         this.renderRoot = root;
     }
 
     @Override
-    public Object getRenderRoot() {
+    public NodePath getRenderRoot() {
         return renderRoot;
     }
 
--- a/modules/graphics/src/main/java/com/sun/prism/sw/SWPipeline.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/sw/SWPipeline.java	Tue Sep 03 09:40:03 2013 -0700
@@ -103,4 +103,9 @@
         // TODO: implement (RT-27375)
         super.dispose();
     }
+
+    @Override
+    public boolean isUploading() {
+        return true;
+    }
 }
--- a/modules/graphics/src/main/java/javafx/animation/Animation.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/java/javafx/animation/Animation.java	Tue Sep 03 09:40:03 2013 -0700
@@ -80,10 +80,10 @@
  * the {@code Animation} from the specified position.
  * <p>
  * Inverting the value of {@link #rate} toggles the play direction.
- * 
+ *
  * @see Timeline
  * @see Transition
- * 
+ *
  * @since JavaFX 2.0
  */
 public abstract class Animation {
@@ -171,7 +171,7 @@
 
     private class CurrentRateProperty extends ReadOnlyDoublePropertyBase {
         private double value;
-        
+
         @Override
         public Object getBean() {
             return Animation.this;
@@ -186,18 +186,18 @@
         public double get() {
             return value;
         }
-        
+
         private void set(double value) {
             this.value = value;
             fireValueChangedEvent();
         }
     }
-    
+
     private class AnimationReadOnlyProperty<T> extends ReadOnlyObjectPropertyBase<T> {
-        
+
         private final String name;
         private T value;
-        
+
         private AnimationReadOnlyProperty(String name, T value) {
             this.name = name;
             this.value = value;
@@ -217,13 +217,13 @@
         public T get() {
             return value;
         }
-        
+
         private void set(T value) {
             this.value = value;
             fireValueChangedEvent();
         }
     }
-    
+
     /**
      * The parent of this {@code Animation}. If this animation has not been
      * added to another animation, such as {@link ParallelTransition} and
@@ -237,7 +237,7 @@
     ClipEnvelope clipEnvelope;
 
     private boolean lastPlayedFinished = false;
-    
+
     private boolean lastPlayedForward = true;
     /**
      * Defines the direction/speed at which the {@code Animation} is expected to
@@ -251,12 +251,12 @@
      * <p>
      * Rate {@code 1.0} is normal play, {@code 2.0} is 2 time normal,
      * {@code -1.0} is backwards, etc...
-     * 
+     *
      * <p>
      * Inverting the rate of a running {@code Animation} will cause the
      * {@code Animation} to reverse direction in place and play back over the
      * portion of the {@code Animation} that has already elapsed.
-     * 
+     *
      * @defaultValue 1.0
      */
     private DoubleProperty rate;
@@ -316,7 +316,7 @@
                 }
 
                 @Override
-                public String getName() { 
+                public String getName() {
                     return "rate";
                 }
             };
@@ -340,12 +340,12 @@
      * {@code currentRate} is set to {@code 0.0} when animation is paused or
      * stopped. {@code currentRate} may also point to different direction during
      * reverse cycles when {@code autoReverse} is {@code true}
-     * 
+     *
      * @defaultValue 0.0
      */
     private ReadOnlyDoubleProperty currentRate;
     private static final double DEFAULT_CURRENT_RATE = 0.0;
-    
+
     private void setCurrentRate(double value) {
         if ((currentRate != null) || (Math.abs(value - DEFAULT_CURRENT_RATE) > EPSILON)) {
             ((CurrentRateProperty)currentRateProperty()).set(value);
@@ -368,7 +368,7 @@
      * {@code Animation}: the time it takes to play from time 0 to the
      * end of the Animation (at the default {@code rate} of
      * 1.0).
-     * 
+     *
      * @defaultValue 0ms
      */
     private ReadOnlyObjectProperty<Duration> cycleDuration;
@@ -400,10 +400,10 @@
      * {@code Animation}, including repeats. A {@code Animation} with a {@code cycleCount}
      * of {@code Animation.INDEFINITE} will have a {@code totalDuration} of
      * {@code Duration.INDEFINITE}.
-     * 
+     *
      * <p>
      * This is set to cycleDuration * cycleCount.
-     * 
+     *
      * @defaultValue 0ms
      */
     private ReadOnlyObjectProperty<Duration> totalDuration;
@@ -432,20 +432,23 @@
         if ((totalDuration != null) || (!DEFAULT_TOTAL_DURATION.equals(newTotalDuration))) {
             ((AnimationReadOnlyProperty<Duration>)totalDurationProperty()).set(newTotalDuration);
         }
-        if (newTotalDuration.lessThan(getCurrentTime())) {
-            jumpTo(newTotalDuration);
+        if (getStatus() == Status.STOPPED) {
+            syncClipEnvelope();
+            if (newTotalDuration.lessThan(getCurrentTime())) {
+                clipEnvelope.jumpTo(fromDuration(newTotalDuration));
+            }
         }
     }
 
     /**
      * Defines the {@code Animation}'s play head position.
-     * 
+     *
      * @defaultValue 0ms
      */
     private CurrentTimeProperty currentTime;
     private long currentTicks;
     private class CurrentTimeProperty extends ReadOnlyObjectPropertyBase<Duration> {
-        
+
         @Override
         public Object getBean() {
             return Animation.this;
@@ -460,14 +463,14 @@
         public Duration get() {
             return getCurrentTime();
         }
-        
+
         @Override
         public void fireValueChangedEvent() {
             super.fireValueChangedEvent();
         }
-        
+
     }
-    
+
     public final Duration getCurrentTime() {
         return TickCalculation.toDuration(currentTicks);
     }
@@ -483,7 +486,7 @@
      * Delays the start of an animation.
      *
      * Cannot be negative. Setting to a negative number will result in {@link IllegalArgumentException}.
-     * 
+     *
      * @defaultValue 0ms
      */
     private ObjectProperty<Duration> delay;
@@ -524,7 +527,7 @@
                             throw new IllegalArgumentException("Cannot set delay to negative value. Setting to Duration.ZERO");
                         }
                 }
-                
+
             };
         }
         return delay;
@@ -539,9 +542,9 @@
      * {@code Animation}. If the value of {@code cycleCount} is changed for a
      * running {@code Animation}, the animation has to be stopped and started again to pick
      * up the new value.
-     * 
+     *
      * @defaultValue 1.0
-     * 
+     *
      */
     private IntegerProperty cycleCount;
     private static final int DEFAULT_CYCLE_COUNT = 1;
@@ -586,12 +589,12 @@
      * {@code Animation} will proceed forward on the first cycle,
      * then reverses on the second cycle, and so on. Otherwise, animation will
      * loop such that each cycle proceeds forward from the start.
-     * 
+     *
      * It is not possible to change the {@code autoReverse} flag of a running
      * {@code Animation}. If the value of {@code autoReverse} is changed for a
      * running {@code Animation}, the animation has to be stopped and started again to pick
      * up the new value.
-     * 
+     *
      * @defaultValue false
      */
     private BooleanProperty autoReverse;
@@ -616,7 +619,7 @@
 
     /**
      * The status of the {@code Animation}.
-     * 
+     *
      * In {@code Animation} can be in one of three states:
      * {@link Status#STOPPED}, {@link Status#PAUSED} or {@link Status#RUNNING}.
      */
@@ -639,7 +642,7 @@
         }
         return status;
     }
-    
+
     private final double targetFramerate;
     private final int resolution;
     private long lastPulse;
@@ -708,11 +711,11 @@
 
     /**
      * Jumps to a given position in this {@code Animation}.
-     * 
+     *
      * If the given time is less than {@link Duration#ZERO}, this method will
      * jump to the start of the animation. If the given time is larger than the
      * duration of this {@code Animation}, this method will jump to the end.
-     * 
+     *
      * @param time
      *            the new position
      * @throws NullPointerException
@@ -735,7 +738,7 @@
         }
 
         lastPlayedFinished = false;
-        
+
         final Duration totalDuration = getTotalDuration();
         time = time.lessThan(Duration.ZERO) ? Duration.ZERO : time
                 .greaterThan(totalDuration) ? totalDuration : time;
@@ -762,7 +765,7 @@
      * There are two predefined cue points {@code "start"} and {@code "end"}
      * which are defined to be at the start respectively the end of this
      * {@code Animation}.
-     * 
+     *
      * @param cuePoint
      *            the name of the cue point
      * @throws NullPointerException
@@ -792,17 +795,17 @@
      * A convenience method to play this {@code Animation} from a predefined
      * position. The position has to be predefined in cue points.
      * Calling this method is equivalent to
-     * 
+     *
      * <pre>
      * <code>
      * animation.jumpTo(cuePoint);
      * animation.play();
      * </code>
      * </pre>
-     * 
+     *
      * Note that unlike {@link #playFromStart()} calling this method will not
      * change the playing direction of this {@code Animation}.
-     * 
+     *
      * @param cuePoint
      *            name of the cue point
      * @throws NullPointerException
@@ -820,17 +823,17 @@
     /**
      * A convenience method to play this {@code Animation} from a specific
      * position. Calling this method is equivalent to
-     * 
+     *
      * <pre>
      * <code>
      * animation.jumpTo(time);
      * animation.play();
      * </code>
      * </pre>
-     * 
+     *
      * Note that unlike {@link #playFromStart()} calling this method will not
      * change the playing direction of this {@code Animation}.
-     * 
+     *
      * @param time
      *            position where to play from
      * @throws NullPointerException
@@ -890,13 +893,12 @@
                     if (lastPlayedFinished) {
                         jumpTo((rate < 0)? getTotalDuration() : Duration.ZERO);
                     }
-                    lastPlayedFinished = false;
                     impl_start(forceSync);
                     startReceiver(TickCalculation.fromDuration(getDelay()));
                     if (Math.abs(rate) < EPSILON) {
                         pauseReceiver();
                     } else {
-                        
+
                     }
                 } else {
                     final EventHandler<ActionEvent> handler = getOnFinished();
@@ -925,7 +927,7 @@
      *      animation.jumpTo(Duration.ZERO);<br>
      *      animation.play();<br>
      *  </code>
-     * 
+     *
      * <p>
      * Note: <ul>
      * <li>{@code playFromStart()} is an asynchronous call, {@code Animation} may
@@ -989,9 +991,9 @@
 
     /**
      * The constructor of {@code Animation}.
-     * 
+     *
      * This constructor allows to define a target framerate.
-     * 
+     *
      * @param targetFramerate
      *            The custom target frame rate for this {@code Animation}
      * @see #getTargetFramerate()
@@ -1039,7 +1041,7 @@
             syncClipEnvelope();
         }
     }
-    
+
     private void syncClipEnvelope() {
         final int publicCycleCount = getCycleCount();
         final int internalCycleCount = (publicCycleCount <= 0)
--- a/modules/graphics/src/main/java/javafx/geometry/Point2D.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/java/javafx/geometry/Point2D.java	Tue Sep 03 09:40:03 2013 -0700
@@ -32,6 +32,12 @@
  * @since JavaFX 2.0
  */
 public class Point2D {
+
+    /**
+     * Point or vector with both coordinates set to 0.
+     */
+    public static final Point2D ZERO = new Point2D(0.0, 0.0);
+
     /**
      * The x coordinate.
      *
--- a/modules/graphics/src/main/java/javafx/geometry/Point3D.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/java/javafx/geometry/Point3D.java	Tue Sep 03 09:40:03 2013 -0700
@@ -33,6 +33,12 @@
  * @since JavaFX 2.0
  */
 public class Point3D {
+
+    /**
+     * Point or vector with all three coordinates set to 0.
+     */
+    public static final Point3D ZERO = new Point3D(0.0, 0.0, 0.0);
+
     /**
      * The x coordinate.
      *
--- a/modules/graphics/src/main/java/javafx/scene/Node.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/java/javafx/scene/Node.java	Tue Sep 03 09:40:03 2013 -0700
@@ -107,6 +107,7 @@
 import com.sun.javafx.Logging;
 import com.sun.javafx.TempState;
 import com.sun.javafx.Utils;
+import com.sun.javafx.accessible.providers.AccessibleProvider;
 import com.sun.javafx.beans.IDProperty;
 import com.sun.javafx.beans.event.AbstractNotifyListener;
 import com.sun.javafx.binding.ExpressionHelper;
@@ -148,12 +149,9 @@
 import com.sun.javafx.scene.traversal.Direction;
 import com.sun.javafx.sg.prism.NGNode;
 import com.sun.javafx.tk.Toolkit;
-import com.sun.javafx.accessible.providers.AccessibleProvider;
+import com.sun.prism.impl.PrismSettings;
 import sun.util.logging.PlatformLogger;
 import sun.util.logging.PlatformLogger.Level;
-import javafx.css.StyleableProperty;
-import javafx.geometry.NodeOrientation;
-import javafx.stage.Window;
 
 /**
  * Base class for scene graph nodes. A scene graph is a set of tree data structures
@@ -536,6 +534,23 @@
     @Deprecated
     public void impl_updatePeer() {
         final NGNode peer = impl_getPeer();
+
+        // For debug / diagnostic purposes, we will copy across a name for this node down to
+        // the NG layer, where we can use the name to figure out what the NGNode represents.
+        // An alternative would be to have a back-reference from the NGNode back to the Node it
+        // is a peer to, however it was felt that this would make it too easy to communicate back
+        // to the Node and possibly violate thread invariants. But of course, we only need to do this
+        // if we're going to print the render graph (otherwise all the work we'd do to keep the name
+        // properly updated would be a waste).
+        if (PrismSettings.printRenderGraph && impl_isDirty(DirtyBits.DEBUG)) {
+            final String id = getId();
+            String className = getClass().getSimpleName();
+            if (className.isEmpty()) {
+                className = getClass().getName();
+            }
+            peer.setName(id == null ? className : id + "(" + className + ")");
+        }
+
         if (impl_isDirty(DirtyBits.NODE_TRANSFORM)) {
             peer.setTransformMatrix(localToParentTx);
         }
@@ -898,7 +913,10 @@
 
                 @Override
                 protected void invalidated() {
-                     impl_reapplyCSS();
+                    impl_reapplyCSS();
+                    if (PrismSettings.printRenderGraph) {
+                        impl_markDirty(DirtyBits.DEBUG);
+                    }
                 }
 
                 @Override
@@ -3835,7 +3853,7 @@
     }
 
     /**
-     * Transforms a point from the coordinate space of the {@link Screen}
+     * Transforms a point from the coordinate space of the {@link javafx.stage.Screen}
      * into the local coordinate space of this {@code Node}.
      * @param screenX x coordinate of a point on a Screen
      * @param screenY y coordinate of a point on a Screen
--- a/modules/graphics/src/main/java/javafx/scene/Scene.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/java/javafx/scene/Scene.java	Tue Sep 03 09:40:03 2013 -0700
@@ -25,6 +25,7 @@
 
 package javafx.scene;
 
+import com.sun.javafx.tk.TKClipboard;
 import javafx.animation.KeyFrame;
 import javafx.animation.Timeline;
 import javafx.application.ConditionalFeature;
@@ -2689,13 +2690,13 @@
          */
         @Override
         public TransferMode dragEnter(double x, double y, double screenX, double screenY,
-                                      TransferMode transferMode)
+                                      TransferMode transferMode, TKClipboard dragboard)
         {
             if (dndGesture == null) {
                 dndGesture = new DnDGesture();
             }
-            Dragboard dragboard = Dragboard.impl_createDragboard(impl_peer, false);
-            dndGesture.dragboard = dragboard;
+            Dragboard db = Dragboard.impl_createDragboard(dragboard);
+            dndGesture.dragboard = db;
             DragEvent dragEvent =
                     new DragEvent(DragEvent.ANY, dndGesture.dragboard, x, y, screenX, screenY,
                             transferMode, null, null, pick(x, y));
@@ -2767,12 +2768,14 @@
     class DragGestureListener implements TKDragGestureListener {
 
        @Override
-       public void dragGestureRecognized(double x, double y, double screenX, double screenY, int button) {
-           Dragboard dragboard = Dragboard.impl_createDragboard(impl_peer, false);
+       public void dragGestureRecognized(double x, double y, double screenX, double screenY,
+                                         int button, TKClipboard dragboard)
+       {
+           Dragboard db = Dragboard.impl_createDragboard(dragboard);
            dndGesture = new DnDGesture();
-           dndGesture.dragboard = dragboard;
+           dndGesture.dragboard = db;
            // TODO: support mouse buttons in DragEvent
-           DragEvent dragEvent = new DragEvent(DragEvent.ANY, dragboard, x, y, screenX, screenY,
+           DragEvent dragEvent = new DragEvent(DragEvent.ANY, db, x, y, screenX, screenY,
                    null, null, null, pick(x, y));
            dndGesture.processRecognized(dragEvent);
            dndGesture = null;
@@ -3135,7 +3138,8 @@
                     return dragboard;
                 }
             }
-            return Dragboard.impl_createDragboard(Scene.this.impl_peer, isDragSource);
+            TKClipboard dragboardPeer = impl_peer.createDragboard(isDragSource);
+            return Dragboard.impl_createDragboard(dragboardPeer);
         }
     }
 
--- a/modules/graphics/src/main/java/javafx/scene/input/DataFormat.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/java/javafx/scene/input/DataFormat.java	Tue Sep 03 09:40:03 2013 -0700
@@ -111,7 +111,7 @@
      *     DataFormat fmt = new DataFormat("text/foo", "text/bar");
      *     Clipboard clipboard = Clipboard.getSystemClipboard();
      *     ClipboardContent content = new ClipboardContent();
-     *     content.pu(fmt, "Hello");
+     *     content.put(fmt, "Hello");
      *     clipboard.setContent(content);
      * </code></pre>
      *
--- a/modules/graphics/src/main/java/javafx/scene/input/Dragboard.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/java/javafx/scene/input/Dragboard.java	Tue Sep 03 09:40:03 2013 -0700
@@ -63,8 +63,8 @@
      * @deprecated This is an internal API that is not intended for use and will be removed in the next version
      */
     @Deprecated
-    public static Dragboard impl_createDragboard(TKScene scene, boolean isDragSource) {
-        return new Dragboard(scene.createDragboard(isDragSource));
+    public static Dragboard impl_createDragboard(TKClipboard peer) {
+        return new Dragboard(peer);
     }
 
     // PENDING_DOC_REVIEW
--- a/modules/graphics/src/main/java/javafx/scene/layout/Background.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/java/javafx/scene/layout/Background.java	Tue Sep 03 09:40:03 2013 -0700
@@ -70,37 +70,37 @@
 @SuppressWarnings("unchecked")
 public final class Background {
     static final CssMetaData<Node,Paint[]> BACKGROUND_COLOR =
-            new SubCssMetaData<Paint[]>("-fx-background-color",
+            new SubCssMetaData<>("-fx-background-color",
                     PaintConverter.SequenceConverter.getInstance(),
                     new Paint[] {Color.TRANSPARENT});
 
     static final CssMetaData<Node,Insets[]> BACKGROUND_RADIUS =
-            new SubCssMetaData<Insets[]>("-fx-background-radius",
+            new SubCssMetaData<>("-fx-background-radius",
                     InsetsConverter.SequenceConverter.getInstance(),
                     new Insets[] {Insets.EMPTY});
 
     static final CssMetaData<Node,Insets[]> BACKGROUND_INSETS =
-            new SubCssMetaData<Insets[]>("-fx-background-insets",
+            new SubCssMetaData<>("-fx-background-insets",
                     InsetsConverter.SequenceConverter.getInstance(),
                     new Insets[] {Insets.EMPTY});
 
     static final CssMetaData<Node,Image[]> BACKGROUND_IMAGE =
-            new SubCssMetaData<Image[]>("-fx-background-image",
+            new SubCssMetaData<>("-fx-background-image",
                     URLConverter.SequenceConverter.getInstance());
 
     static final CssMetaData<Node,RepeatStruct[]> BACKGROUND_REPEAT =
-            new SubCssMetaData<RepeatStruct[]>("-fx-background-repeat",
+            new SubCssMetaData<>("-fx-background-repeat",
                     RepeatStructConverter.getInstance(),
                     new RepeatStruct[] {new RepeatStruct(BackgroundRepeat.REPEAT,
                                                          BackgroundRepeat.REPEAT) });
 
     static final CssMetaData<Node,BackgroundPosition[]> BACKGROUND_POSITION =
-            new SubCssMetaData<BackgroundPosition[]>("-fx-background-position",
+            new SubCssMetaData<>("-fx-background-position",
                     LayeredBackgroundPositionConverter.getInstance(),
                     new BackgroundPosition[] { BackgroundPosition.DEFAULT });
 
     static final CssMetaData<Node,BackgroundSize[]> BACKGROUND_SIZE =
-            new SubCssMetaData<BackgroundSize[]>("-fx-background-size",
+            new SubCssMetaData<>("-fx-background-size",
                     LayeredBackgroundSizeConverter.getInstance(),
                     new BackgroundSize[] { BackgroundSize.DEFAULT } );
 
@@ -176,6 +176,13 @@
     final boolean hasPercentageBasedOpaqueFills;
 
     /**
+     * True if there are any fills that are in some way based on the size of the region.
+     * For example, if a CornerRadii on the fill is percentage based in either or both
+     * dimensions.
+     */
+    final boolean hasPercentageBasedFills;
+
+    /**
      * The cached hash code computation for the Background. One very big
      * reason for making Background immutable was to make it possible to
      * cache and reuse the same Background instance for multiple
@@ -253,6 +260,7 @@
         // The cumulative insets
         double outerTop = 0, outerRight = 0, outerBottom = 0, outerLeft = 0;
         boolean hasPercentOpaqueInsets = false;
+        boolean hasPercentFillRadii = false;
         boolean opaqueFill = false;
 
         // If the fills is empty or null then we know we can just use the shared
@@ -279,9 +287,12 @@
                     outerBottom = outerBottom <= fillBottom ? outerBottom : fillBottom; // min
                     outerLeft = outerLeft <= fillLeft ? outerLeft : fillLeft; // min
 
+                    // The common case is to NOT have percent based radii
+                    final boolean b = fill.getRadii().hasPercentBasedRadii;
+                    hasPercentFillRadii |= b;
                     if (fill.fill.isOpaque()) {
                         opaqueFill = true;
-                        if (fill.getRadii().hasPercentBasedRadii) {
+                        if (b) {
                             hasPercentOpaqueInsets = true;
                         }
                     }
@@ -289,6 +300,7 @@
             }
             this.fills = new UnmodifiableArrayList<>(noNulls, size);
         }
+        hasPercentageBasedFills = hasPercentFillRadii;
 
         // This ensures that we either have outsets of 0, if all the insets were positive,
         // or a value greater than zero if they were negative.
@@ -337,6 +349,18 @@
     }
 
     /**
+     * Gets whether the fill of this Background is based on percentages (that is, relative to the
+     * size of the region being styled). Specifically, this returns true if any of the CornerRadii
+     * on any of the fills on this Background has a radius that is based on percentages.
+     *
+     * @return True if any CornerRadii of any BackgroundFill on this background would return true, false otherwise.
+     * @since JavaFX 8.0
+     */
+    public boolean isFillPercentageBased() {
+        return hasPercentageBasedFills;
+    }
+
+    /**
      * Computes the opaque insets for a region with the specified width and height. This call
      * must be made whenever the width or height of the region change, because the opaque insets
      * are based on background fills, and the corner radii of a background fill can be percentage
--- a/modules/graphics/src/main/java/javafx/scene/paint/PhongMaterial.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/java/javafx/scene/paint/PhongMaterial.java	Tue Sep 03 09:40:03 2013 -0700
@@ -454,7 +454,7 @@
     }
 
     @Override public String toString() {
-        return "PGPhongMaterial[" + "diffuseColor=" + getDiffuseColor() +
+        return "PhongMaterial[" + "diffuseColor=" + getDiffuseColor() +
                 ", specularColor=" + getSpecularColor() +
                 ", specularPower=" + getSpecularPower() +
                 ", diffuseMap=" + getDiffuseMap() +
--- a/modules/graphics/src/main/java/javafx/scene/shape/MeshView.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/java/javafx/scene/shape/MeshView.java	Tue Sep 03 09:40:03 2013 -0700
@@ -36,6 +36,7 @@
 import javafx.beans.property.SimpleObjectProperty;
 import javafx.beans.value.ChangeListener;
 import javafx.beans.value.ObservableValue;
+import javafx.beans.value.WeakChangeListener;
 
 /**
  * The {@code MeshView} class defines a surface with the specified 3D
@@ -74,28 +75,34 @@
         return mesh == null ? null : mesh.get();
     }
 
-    private final ChangeListener<Boolean> meshListener = new ChangeListener<Boolean>() {
-        @Override public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
-            if (newValue) {
-                impl_markDirty(DirtyBits.MESH_GEOM);
-                impl_geomChanged();
-            }
-        }
-    };
-
     public final ObjectProperty<Mesh> meshProperty() {
         if (mesh == null) {
             mesh = new SimpleObjectProperty<Mesh>(MeshView.this, "mesh") {
+                
                 private Mesh old = null;
+                private final ChangeListener<Boolean> meshChangeListener =
+                        new ChangeListener<Boolean>() {
+                            
+                    @Override
+                    public void changed(ObservableValue<? extends Boolean> observable,
+                            Boolean oldValue, Boolean newValue) {
+                        if (newValue) {
+                            impl_markDirty(DirtyBits.MESH_GEOM);
+                            impl_geomChanged();
+                        }
+                    }
+                };
+                private final WeakChangeListener<Boolean> weakMeshChangeListener =
+                        new WeakChangeListener(meshChangeListener);
 
                 @Override
                 protected void invalidated() {
                     if (old != null) {
-                        old.dirtyProperty().removeListener(meshListener);
+                        old.dirtyProperty().removeListener(weakMeshChangeListener);
                     }
                     Mesh newMesh = get();
                     if (newMesh != null) {
-                        newMesh.dirtyProperty().addListener(meshListener);
+                        newMesh.dirtyProperty().addListener(weakMeshChangeListener);
                     }
                     impl_markDirty(DirtyBits.MESH);
                     impl_markDirty(DirtyBits.MESH_GEOM);
--- a/modules/graphics/src/main/java/javafx/scene/shape/Shape3D.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/java/javafx/scene/shape/Shape3D.java	Tue Sep 03 09:40:03 2013 -0700
@@ -38,6 +38,7 @@
 import javafx.beans.property.SimpleObjectProperty;
 import javafx.beans.value.ChangeListener;
 import javafx.beans.value.ObservableValue;
+import javafx.beans.value.WeakChangeListener;
 import javafx.scene.Node;
 import javafx.scene.paint.Material;
 import javafx.scene.paint.PhongMaterial;
@@ -96,28 +97,34 @@
     public final Material getMaterial() {
         return material == null ? null : material.get();
     }
-
-    private final ChangeListener<Boolean> materialListener = new ChangeListener<Boolean>() {
-        @Override public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
-            if (newValue) {
-                impl_markDirty(DirtyBits.MATERIAL);
-            }
-        }
-    };
- 
+   
     public final ObjectProperty<Material> materialProperty() {
         if (material == null) {
             material = new SimpleObjectProperty<Material>(Shape3D.this,
                     "material") {
 
                 private Material old = null;
+                private final ChangeListener<Boolean> materialChangeListener =
+                        new ChangeListener<Boolean>() {
+                            
+                    @Override
+                    public void changed(ObservableValue<? extends Boolean> observable,
+                            Boolean oldValue, Boolean newValue) {
+                        if (newValue) {
+                            impl_markDirty(DirtyBits.MATERIAL);
+                        }
+                    }
+                };
+                private final WeakChangeListener<Boolean> weakMaterialChangeListener =
+                        new WeakChangeListener(materialChangeListener);
+
                 @Override protected void invalidated() {
                     if (old != null) {
-                        old.impl_dirtyProperty().removeListener(materialListener);
+                        old.impl_dirtyProperty().removeListener(weakMaterialChangeListener);
                     }
                     Material newMaterial = get();
                     if (newMaterial != null) {
-                        newMaterial.impl_dirtyProperty().addListener(materialListener);
+                        newMaterial.impl_dirtyProperty().addListener(weakMaterialChangeListener);
                     }
                     impl_markDirty(DirtyBits.MATERIAL);
                     impl_geomChanged();
--- a/modules/graphics/src/main/java/javafx/scene/shape/TriangleMesh.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/java/javafx/scene/shape/TriangleMesh.java	Tue Sep 03 09:40:03 2013 -0700
@@ -126,7 +126,7 @@
      * @return {@code ObservableFloatArray} of points where each point is
      * represented by 3 float values x, y and z, in that order.
      */    
-    public ObservableFloatArray getPoints() {
+    public final ObservableFloatArray getPoints() {
         return points;
     }
 
@@ -137,7 +137,7 @@
      * where each texture coordinate is represented by 2 float values: u and v,
      * in that order
      */    
-    public ObservableFloatArray getTexCoords() {
+    public final ObservableFloatArray getTexCoords() {
         return texCoords;
     }
  
@@ -152,7 +152,7 @@
      * Both indices are in terms of vertices (points or texCoords), not individual
      * floats.
      */    
-    public ObservableIntegerArray getFaces() {
+    public final ObservableIntegerArray getFaces() {
         return faces;
     }
 
@@ -178,7 +178,7 @@
      * <p> Note: If faceSmoothingGroups is not empty, is size must
      * be equal to number of faces.
      */    
-    public ObservableIntegerArray getFaceSmoothingGroups() {
+    public final ObservableIntegerArray getFaceSmoothingGroups() {
         return faceSmoothingGroups;
     }
 
--- a/modules/graphics/src/main/native-glass/gtk/GlassView.cpp	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/native-glass/gtk/GlassView.cpp	Tue Sep 03 09:40:03 2013 -0700
@@ -118,13 +118,16 @@
   (JNIEnv * env, jobject obj, jlong ptr, jlong parent)
 {
     GlassView* view = JLONG_TO_GLASSVIEW(ptr);
-    if (view->current_window && !parent) {
+    bool is_removing = view->current_window && !parent;
+
+    view->current_window = (WindowContext*)JLONG_TO_PTR(parent);
+
+    if (is_removing) {
         env->CallVoidMethod(obj, jViewNotifyView, com_sun_glass_events_ViewEvent_REMOVE);
     } else {
         env->CallVoidMethod(obj, jViewNotifyView, com_sun_glass_events_ViewEvent_ADD);
     }
     CHECK_JNI_EXCEPTION(env);
-    view->current_window = (WindowContext*)JLONG_TO_PTR(parent);
 }
 
 /*
--- a/modules/graphics/src/main/native-glass/gtk/glass_window.cpp	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/native-glass/gtk/glass_window.cpp	Tue Sep 03 09:40:03 2013 -0700
@@ -71,6 +71,9 @@
 }
 
 void WindowContextBase::process_focus(GdkEventFocus* event) {
+    if (!event->in && WindowContextBase::sm_mouse_drag_window == this) {
+        ungrab_mouse_drag_focus();
+    }
     if (!event->in && WindowContextBase::sm_grab_window == this) {
         ungrab_focus();
     }
@@ -213,6 +216,17 @@
         }
     }
 
+    // Upper layers expects from us Windows behavior:
+    // all mouse events should be delivered to window where drag begins
+    // and no exit/enter event should be reported during this drag.
+    // We can grab mouse pointer for these needs.
+    if (press) {
+        grab_mouse_drag_focus();
+    } else if ((event->state & MOUSE_BUTTONS_MASK)
+            && !(state & MOUSE_BUTTONS_MASK)) { // all buttons released
+        ungrab_mouse_drag_focus();
+    }
+
     jint button = gtk_button_number_to_mouse_button(event->button);
 
     if (jview && button != com_sun_glass_events_MouseEvent_BUTTON_NONE) {
@@ -234,17 +248,6 @@
             CHECK_JNI_EXCEPTION(mainEnv)
         }
     }
-
-    // Upper layers expects from us Windows behavior:
-    // all mouse events should be delivered to window where drag begins 
-    // and no exit/enter event should be reported during this drag.
-    // We can grab mouse pointer for these needs.
-    if (press) {
-        grab_mouse_drag_focus();
-    } else if ((event->state & MOUSE_BUTTONS_MASK)
-            && !(state & MOUSE_BUTTONS_MASK)) { // all buttons released
-        ungrab_mouse_drag_focus();
-    }
 }
 
 void WindowContextBase::process_mouse_motion(GdkEventMotion* event) {
@@ -823,9 +826,13 @@
                                            + geometry.extents.right;
     geometry.current_height = event->height + geometry.extents.top
                                              + geometry.extents.bottom;
-
-    int x, y;
-    gtk_window_get_position(GTK_WINDOW(gtk_widget), &x, &y);
+    gint x, y;
+    if (gtk_window_get_decorated(GTK_WINDOW(gtk_widget))) {
+        gtk_window_get_position(GTK_WINDOW(gtk_widget), &x, &y);
+    } else {
+        x = event->x;
+        y = event->y;
+    }
 
     if (stale_config_notifications == 0) {
         if ((geometry_get_content_width(&geometry) != event->width)
--- a/modules/graphics/src/main/native-glass/lens/input/android/androidLens.c	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/native-glass/lens/input/android/androidLens.c	Tue Sep 03 09:40:03 2013 -0700
@@ -76,11 +76,12 @@
         int yabs) {
     
    ATTACH_JNI_THREAD();
-   lens_wm_notifyTouchEvent(env,
-           state,
-           id,
-           xabs,
-           yabs);
+   lens_wm_notifyMultiTouchEvent(env,
+           1,
+           &state,
+           &id,
+           &xabs,
+           &yabs);
                    
    if (sendAlsoButtonEvent) {
         lens_wm_notifyButtonEvent(env,
--- a/modules/graphics/src/main/native-glass/lens/input/udev/udevInput.c	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/native-glass/lens/input/udev/udevInput.c	Tue Sep 03 09:40:03 2013 -0700
@@ -78,7 +78,7 @@
 
 // event related macros
 #define MAX_NUM_OF_DEVICES_SUPPORTED 20  // max number of concurrent connected devices
-#define EVENTS_PER_READ 32 // number of queued events to try to handle at a time
+#define EVENTS_PER_READ 150 // number of queued events to try to handle at a time
 
 
 //keyboard macros
@@ -196,6 +196,10 @@
     struct timeval timeout;
     void (*onTimeoutFunc)(struct _LensInputDevice *);
 
+    /* buffer for input events */
+    struct input_event      *readInputEvents;
+    int                     readOffset;
+
     struct _LensInputDevice *previousDevice;
     struct _LensInputDevice *nextDevice;
 
@@ -485,6 +489,15 @@
     device->timeout.tv_sec = 0;
     device->onTimeoutFunc = NULL;
 
+    device->readOffset = 0;
+    device->readInputEvents = calloc(EVENTS_PER_READ, sizeof(struct input_event));
+    if (device->readInputEvents == NULL) {
+        GLASS_LOG_SEVERE("Failed to allocate readInputEvents buffer");
+        lens_input_deviceRelease(env, device);
+        return NULL;
+    }
+
+
     info = lens_input_deviceInfoAllocateAndInit(udev_device, device);
     if (!info) {
         GLASS_LOG_FINE("Failed to allocate LensInputDeviceInfo");
@@ -676,7 +689,7 @@
 }
 
 static LensResult lens_input_deviceOpen(JNIEnv *env, LensInputDevice *device) {
-    device->fd = open(device->info->devNode, O_RDONLY);
+    device->fd = open(device->info->devNode, O_RDONLY|O_NONBLOCK);
     GLASS_LOG_FINE("open(%s) returned %i", device->info->devNode, device->fd);
 
     if (device->fd == -1) {
@@ -936,7 +949,7 @@
 
         //init
         memset(&epollEvent, 0, sizeof(epollEvent));
-        epollEvent.events = EPOLLIN | EPOLLET;
+        epollEvent.events = EPOLLIN;
         epollEvent.data.ptr = device;
 
         //add device to epoll list
@@ -1033,7 +1046,6 @@
 void lens_input_eventLoop(JNIEnv *env, void *handle) {
 
     int numOfEpollEvents;
-    struct input_event events[EVENTS_PER_READ];
     struct epoll_event epollEvent;
     struct epoll_event *epollEvents = calloc(MAX_NUM_OF_DEVICES_SUPPORTED,
                                              sizeof(struct epoll_event));
@@ -1047,6 +1059,7 @@
         GLASS_LOG_SEVERE("Failed to alloc epollEvents - [errno %i] %s", errno, strerror(errno));
         exit(-1);
     }
+
     GLASS_LOG_FINE("Allocated epollEvents %p", epollEvents);
 
     useTestInput = testInputPath != NULL && strlen(testInputPath) > 0;
@@ -1087,7 +1100,7 @@
 
     while (doLoop) {
         int epoll_errno;
-        int epoll_timeout = lens_input_eventLoop_checkTimeout();;
+        int epoll_timeout = lens_input_eventLoop_checkTimeout();
 
         //Before wait release the lock
         GLASS_LOG_FINER("Releasing lock before epoll_wait()");
@@ -1162,37 +1175,56 @@
             if (device) {
                 int numOfEvents;
                 int eventIndex;
-
-                int numOfBytesRead = read(device->fd, events, sizeof(struct input_event) * EVENTS_PER_READ);
-
-                if (numOfBytesRead < 0 && errno != EINTR) {
-                    GLASS_LOG_SEVERE("error reading %s, fd=%i, errno=%i (%s)",
-                                     device->info->name, device->fd, errno, strerror(errno));
+                int numOfBytesRead;
+                int numOfRemainingBytes;
+                char* readBuffer = (char*)(device->readInputEvents);
+                const int readBufferSize = (int)sizeof(struct input_event) * EVENTS_PER_READ;
+
+                do {
+                    numOfBytesRead = read(device->fd, readBuffer + device->readOffset, 
+                                          readBufferSize - device->readOffset);
+
+                    if (numOfBytesRead > 0) {
+                        device->readOffset += numOfBytesRead;
+                    }
+
+                } while ((device->readOffset < readBufferSize ) && 
+                         (numOfBytesRead > 0 || (numOfBytesRead < 0 && errno == EINTR)));
+
+
+                if (numOfBytesRead < 0 && errno != EINTR && errno != EWOULDBLOCK) {
+                    GLASS_LOG_SEVERE("error reading %s, read offset=%i fd=%i, errno=%i (%s)",
+                                     device->info->name, device->readOffset, device->fd, 
+                                     errno, strerror(errno));
                     lens_input_epollRemoveDevice(device);
-                    continue;
-                } else if (numOfBytesRead < 0 && errno == EINTR) {
-                    GLASS_LOG_WARNING("reading interrupted on %s, fd=%i",
-                                      device->info->name, device->fd);
-                    continue;
-                } else {
-
-                    numOfEvents = numOfBytesRead / (int)sizeof(struct input_event);
+                    continue; // of for-loop
+                } 
+
+                numOfEvents = device->readOffset / (int)sizeof(struct input_event);
 
                     GLASS_LOG_FINEST("Got event on %s, count=%i",
                                      device->info->name, numOfEvents);
 
 
-                    for (eventIndex = 0; eventIndex < numOfEvents; eventIndex ++) {
-
-                        lens_input_printEvent(events[eventIndex]);
-
-                        if (device->isKeyboard) {
-                            lens_input_keyEvents_handleEvent(device, &events[eventIndex]);
-                        } else if (device->isPointer || device->isTouch) {
-                            lens_input_pointerEvents_handleEvent(device, &events[eventIndex]);
-                        }
+                for (eventIndex = 0; eventIndex < numOfEvents; eventIndex ++) {
+
+                    lens_input_printEvent(device->readInputEvents[eventIndex]);
+
+                    if (device->isKeyboard) {
+                        lens_input_keyEvents_handleEvent(device, &device->readInputEvents[eventIndex]);
+                    } else if (device->isPointer || device->isTouch) {
+                        lens_input_pointerEvents_handleEvent(device, &device->readInputEvents[eventIndex]);
                     }
                 }
+           
+                numOfRemainingBytes = device->readOffset % (int)sizeof(struct input_event);
+                if (numOfRemainingBytes == 0) {
+                    // most (if not all) of the times
+                    device->readOffset = 0;
+                } else {
+                    memmove(readBuffer, readBuffer + device->readOffset - numOfRemainingBytes, numOfRemainingBytes);
+                    device->readOffset = numOfRemainingBytes;
+                }           
 
             } else {
                 GLASS_LOG_WARNING("Null device, skipping event");
@@ -1200,6 +1232,8 @@
             }
         }//for
     }//while
+
+    free(epollEvents);
 }
 
 ////// mouse and touch events handling
@@ -2098,7 +2132,6 @@
     }
 
     device->state = NULL;
-
 }
 
 /**
@@ -2124,6 +2157,10 @@
         GLASS_LOG_FINER("Freeing deviceInfo");
         lens_input_deviceInfoRelease(device);
 
+        if (device->readInputEvents != NULL) {
+            free(device->readInputEvents);
+        }
+
         GLASS_LOG_FINE("free(%p) (device)", device);
         free(device);
     }
@@ -2320,127 +2357,211 @@
  */
 static void lens_input_printEvent(struct input_event event) {
     char *tmp;
-
+    
     GLASS_IF_LOG_FINEST {
 
         switch (event.type) {
+            case EV_SYN:
+                switch (event.code){
+                    case SYN_REPORT:
+                        tmp = "SYN_REPORT";
+                        break;
+                    case SYN_CONFIG:
+                        tmp = "SYN_CONFIG";
+                        break;
+                    case SYN_MT_REPORT:
+                        tmp = "SYN_MT_REPORT";
+                        break;
+                    case SYN_DROPPED:
+                        tmp = "SYN_DROPPED";
+                        break;
+                    default:
+                        tmp = NULL;
+                        break;
+                }
+                if (tmp != NULL) {
+                    GLASS_LOG_FINEST("EV_SYN %s %i", tmp, event.value);
+                } else {
+                    GLASS_LOG_FINEST("EV_SYN 0x%x %i", event.code, event.value);
+                }
+                break;
             case EV_KEY:
-                if (event.code > BTN_MISC) {
-                    GLASS_LOG_FINEST("Button %d %s",
-                    event.code & 0xff,
-                    event.value ? "press" : "release");
+                switch (event.code){
+                    case BTN_TOUCH:
+                        tmp = "BTN_TOUCH";
+                        break;
+                    case BTN_TOOL_DOUBLETAP:
+                        tmp = "BTN_TOOL_DOUBLETAP";
+                        break;
+                    case BTN_TOOL_TRIPLETAP:
+                        tmp = "BTN_TOOL_TRIPLETAP";
+                        break;
+                    case BTN_TOOL_QUADTAP:
+                        tmp = "BTN_TOOL_QUADTAP";
+                        break;
+                    default:
+                        tmp = NULL;
+                        break;
+                }
+                if (tmp != NULL) {
+                    GLASS_LOG_FINEST("EV_KEY %s %i", tmp, event.value);
                 } else {
-                    GLASS_LOG_FINEST("Key %d (0x%x) %s",
-                                     event.code & 0xff,
-                                     event.code & 0xff,
-                                     event.value ? "press" : "release");
+                    GLASS_LOG_FINEST("EV_KEY 0x%x %i", event.code, event.value);
                 }
                 break;
             case EV_REL:
                 switch (event.code) {
                     case REL_X:
-                        tmp = "X";
+                        tmp = "REL_X";
                         break;
                     case REL_Y:
-                        tmp = "Y";
+                        tmp = "REL_Y";
                         break;
                     case REL_HWHEEL:
-                        tmp = "HWHEEL";
+                        tmp = "REL_HWHEEL";
                         break;
                     case REL_DIAL:
-                        tmp = "DIAL";
+                        tmp = "REL_DIAL";
                         break;
                     case REL_WHEEL:
-                        tmp = "WHEEL";
+                        tmp = "REL_WHEEL";
                         break;
                     case REL_MISC:
-                        tmp = "MISC";
+                        tmp = "REL_MISC";
                         break;
                     default:
-                        tmp = "UNKNOWN";
+                        tmp = NULL;
                         break;
                 }
-                GLASS_LOG_FINEST("Relative %s %d", tmp, event.value);
+                if (tmp != NULL) {
+                    GLASS_LOG_FINEST("EV_REL %s %i", tmp, event.value);
+                } else {
+                    GLASS_LOG_FINEST("EV_REL 0x%x %i", event.code, event.value);
+                }
                 break;
             case EV_ABS:
                 switch (event.code) {
                     case ABS_X:
-                        tmp = "X";
+                        tmp = "ABS_X";
                         break;
                     case ABS_Y:
-                        tmp = "Y";
+                        tmp = "ABS_Y";
                         break;
                     case ABS_Z:
-                        tmp = "Z";
+                        tmp = "ABS_Z";
                         break;
                     case ABS_RX:
-                        tmp = "RX";
+                        tmp = "ABS_RX";
                         break;
                     case ABS_RY:
-                        tmp = "RY";
+                        tmp = "ABS_RY";
                         break;
                     case ABS_RZ:
-                        tmp = "RZ";
+                        tmp = "ABS_RZ";
                         break;
                     case ABS_THROTTLE:
-                        tmp = "THROTTLE";
+                        tmp = "ABS_THROTTLE";
                         break;
                     case ABS_RUDDER:
-                        tmp = "RUDDER";
+                        tmp = "ABS_RUDDER";
                         break;
                     case ABS_WHEEL:
-                        tmp = "WHEEL";
+                        tmp = "ABS_WHEEL";
                         break;
                     case ABS_GAS:
-                        tmp = "GAS";
+                        tmp = "ABS_GAS";
                         break;
                     case ABS_BRAKE:
-                        tmp = "BRAKE";
+                        tmp = "ABS_BRAKE";
                         break;
                     case ABS_HAT0X:
-                        tmp = "HAT0X";
+                        tmp = "ABS_HAT0X";
                         break;
                     case ABS_HAT0Y:
-                        tmp = "HAT0Y";
+                        tmp = "ABS_HAT0Y";
                         break;
                     case ABS_HAT1X:
-                        tmp = "HAT1X";
+                        tmp = "ABS_HAT1X";
                         break;
                     case ABS_HAT1Y:
-                        tmp = "HAT1Y";
+                        tmp = "ABS_HAT1Y";
                         break;
                     case ABS_HAT2X:
-                        tmp = "HAT2X";
+                        tmp = "ABS_HAT2X";
                         break;
                     case ABS_HAT2Y:
-                        tmp = "HAT2Y";
+                        tmp = "ABS_HAT2Y";
                         break;
                     case ABS_HAT3X:
-                        tmp = "HAT3X";
+                        tmp = "ABS_HAT3X";
                         break;
                     case ABS_HAT3Y:
-                        tmp = "HAT3Y";
+                        tmp = "ABS_HAT3Y";
                         break;
                     case ABS_PRESSURE:
-                        tmp = "PRESSURE";
+                        tmp = "ABS_PRESSURE";
                         break;
                     case ABS_DISTANCE:
-                        tmp = "DISTANCE";
+                        tmp = "ABS_DISTANCE";
                         break;
                     case ABS_TILT_X:
-                        tmp = "TILT_X";
+                        tmp = "ABS_TILT_X";
                         break;
                     case ABS_TILT_Y:
-                        tmp = "TILT_Y";
+                        tmp = "ABS_TILT_Y";
                         break;
                     case ABS_MISC:
-                        tmp = "MISC";
+                        tmp = "ABS_MISC";
                         break;
+                    case ABS_MT_SLOT:
+                        tmp = "ABS_MT_SLOT";
+                        break;
+                    case ABS_MT_TOUCH_MAJOR:
+                        tmp = "ABS_MT_TOUCH_MAJOR";
+                        break;
+                    case ABS_MT_TOUCH_MINOR:
+                        tmp = "ABS_MT_TOUCH_MINOR";
+                        break;
+                    case ABS_MT_WIDTH_MAJOR:
+                        tmp = "ABS_MT_WIDTH_MAJOR";
+                        break;
+                    case ABS_MT_WIDTH_MINOR:
+                        tmp = "ABS_MT_WIDTH_MINOR";
+                        break;
+                    case ABS_MT_ORIENTATION:
+                        tmp = "ABS_MT_ORIENTATION";
+                        break;
+                    case ABS_MT_POSITION_X:
+                        tmp = "ABS_MT_POSITION_X";
+                        break;
+                    case ABS_MT_POSITION_Y:
+                        tmp = "ABS_MT_POSITION_Y";
+                        break;
+                    case ABS_MT_TOOL_TYPE:
+                        tmp = "ABS_MT_TOOL_TYPE";
+                        break;
+                    case ABS_MT_BLOB_ID:
+                        tmp = "ABS_MT_BLOB_ID";
+                        break;
+                    case ABS_MT_TRACKING_ID:
+                        tmp = "ABS_MT_TRACKING_ID";
+                        break;
+                    case ABS_MT_PRESSURE:
+                        tmp = "ABS_MT_PRESSURE";
+                        break;
+                    case ABS_MT_DISTANCE:
+                        tmp = "ABS_MT_DISTANCE";
+                        break;
+
                     default:
-                        tmp = "UNKNOWN";
+                        tmp = NULL;
                         break;
                 }
-                GLASS_LOG_FINEST("Absolute %s %d", tmp, event.value);
+                if (tmp != NULL) {
+                    GLASS_LOG_FINEST("EV_ABS %s %i", tmp, event.value);
+                } else {
+                    GLASS_LOG_FINEST("EV_ABS 0x%x %i", event.code, event.value);
+                }
                 break;
             case EV_MSC:
                 GLASS_LOG_FINEST("Misc");
@@ -2457,6 +2578,8 @@
             case EV_FF:
                 GLASS_LOG_FINEST("FF");
                 break;
+            default:
+                GLASS_LOG_FINEST("Event type=0x%x code=%i value=%i", event.type, event.code, event.value);
                 break;
         }
 
@@ -2729,6 +2852,14 @@
         device->timeout.tv_sec = 0;
         device->onTimeoutFunc = NULL;
 
+        device->readOffset = 0;
+        device->readInputEvents = calloc(EVENTS_PER_READ, sizeof(struct input_event));
+        if (device->readInputEvents == NULL) {
+            GLASS_LOG_SEVERE("Failed to allocate readInputEvents buffer");
+            lens_input_deviceRelease(env, device);
+            return LENS_FAILED;
+        }
+
         GLASS_LOG_FINE("Reading device ID");
         if (lens_input_testInputRead(&id, sizeof(id))) {
             lens_input_deviceRelease(env, device);
--- a/modules/graphics/src/main/native-glass/mac/GlassKey.m	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/native-glass/mac/GlassKey.m	Tue Sep 03 09:40:03 2013 -0700
@@ -362,7 +362,7 @@
     }
     else
     {
-        return [NSString stringWithFormat:@"%c", jKeyCode];
+        return [[NSString stringWithFormat:@"%c", jKeyCode] lowercaseString];
     }
 
 }
--- a/modules/graphics/src/main/native-glass/mac/GlassLayer3D.m	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/native-glass/mac/GlassLayer3D.m	Tue Sep 03 09:40:03 2013 -0700
@@ -186,11 +186,15 @@
 - (void)flush
 {
     [(GlassOffscreen*)_glassOffscreen blitFromOffscreen:(GlassOffscreen*)_painterOffscreen];
-    [[NSRunLoop mainRunLoop] performSelector:@selector(setNeedsDisplay)
-                                      target:[self->_glassOffscreen getLayer]
-                                    argument:nil
-                                       order:0
-                                       modes:allModes];
+    if ([NSThread isMainThread]) {
+        [[self->_glassOffscreen getLayer] setNeedsDisplay];
+    } else {
+        [[NSRunLoop mainRunLoop] performSelector:@selector(setNeedsDisplay)
+                                          target:[self->_glassOffscreen getLayer]
+                                        argument:nil
+                                           order:0
+                                           modes:allModes];
+    }
 }
 
 - (uint32_t)getRemoteLayerIdForServer:(NSString*)serverName
--- a/modules/graphics/src/main/native-glass/mac/GlassView3D.m	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/native-glass/mac/GlassView3D.m	Tue Sep 03 09:40:03 2013 -0700
@@ -617,8 +617,8 @@
         NSSize size = [self bounds].size;
         if ((size.width != w) || (size.height != h))
         {
-            //NSLog(@"Glass View3D size: %dx%d, but pixels size: %dx%d", (int)size.width, (int)size.height, (int)w, (int)h);
-            //glClear(GL_COLOR_BUFFER_BIT);
+            // This could happen on live resize, clear the FBO to avoid rendering garbage
+            glClear(GL_COLOR_BUFFER_BIT);
         }
         
         glMatrixMode(GL_PROJECTION);
@@ -651,8 +651,8 @@
     glDisable(GL_TEXTURE_RECTANGLE_EXT);
     
     glFinish();
-    
-    [[self layer] setNeedsDisplay];
+
+    // The layer will be notified about redraw in _end()
 }
 
 - (GlassViewDelegate*)delegate
--- a/modules/graphics/src/main/native-glass/win/KeyTable.cpp	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/native-glass/win/KeyTable.cpp	Tue Sep 03 09:40:03 2013 -0700
@@ -198,6 +198,36 @@
     modifiers = 0;
 }
 
+BOOL IsExtendedKey(UINT vkey) {
+    switch (vkey) {
+        case VK_INSERT:
+        case VK_DELETE:
+        case VK_HOME:
+        case VK_END:
+        case VK_PRIOR:
+        case VK_NEXT:
+        case VK_LEFT:
+        case VK_UP:
+        case VK_RIGHT:
+        case VK_DOWN:
+        case VK_NUMLOCK:
+        case VK_NUMPAD0:
+        case VK_NUMPAD1:
+        case VK_NUMPAD2:
+        case VK_NUMPAD3:
+        case VK_NUMPAD4:
+        case VK_NUMPAD5:
+        case VK_NUMPAD6:
+        case VK_NUMPAD7:
+        case VK_NUMPAD8:
+        case VK_NUMPAD9:
+        case VK_SNAPSHOT:
+            return true;
+        default:
+            return false;
+    }
+}
+
 /*
  * Class:     com_sun_glass_events_KeyEvent
  * Method:    _getKeyCodeForChar
--- a/modules/graphics/src/main/native-glass/win/KeyTable.h	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/native-glass/win/KeyTable.h	Tue Sep 03 09:40:03 2013 -0700
@@ -28,5 +28,6 @@
 
 jint WindowsKeyToJavaKey(UINT wKey);
 void JavaKeyToWindowsKey(jint jkey, UINT &vkey, UINT &modifiers);
+BOOL IsExtendedKey(UINT vkey);
 
 #endif // _KEY_TABLE_
--- a/modules/graphics/src/main/native-glass/win/Robot.cpp	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/native-glass/win/Robot.cpp	Tue Sep 03 09:40:03 2013 -0700
@@ -40,7 +40,20 @@
         return FALSE;
     } else {
         UINT scancode = ::MapVirtualKey(vkey, 0);
-        ::keybd_event(vkey, scancode, isPress ? 0 : KEYEVENTF_KEYUP, 0);
+
+        INPUT keyInput = {0};
+        keyInput.type = INPUT_KEYBOARD;
+        keyInput.ki.wVk = vkey;
+        keyInput.ki.wScan = scancode;
+        keyInput.ki.time = 0;
+        keyInput.ki.dwExtraInfo = 0;
+        keyInput.ki.dwFlags = isPress ?  0 : KEYEVENTF_KEYUP;
+        if (IsExtendedKey(vkey)) {
+            keyInput.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
+        }
+
+        ::SendInput(1, &keyInput, sizeof(keyInput));
+
         return TRUE;
     }
 }
--- a/modules/graphics/src/main/native-glass/win/ViewContainer.cpp	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/main/native-glass/win/ViewContainer.cpp	Tue Sep 03 09:40:03 2013 -0700
@@ -78,6 +78,7 @@
     m_bTrackingMouse(FALSE),
     m_manipProc(NULL),
     m_inertiaProc(NULL),
+    m_manipEventSink(NULL),
     m_gestureSupportCls(NULL),
     m_lastMouseMovePosition(-1),
     m_mouseButtonDownCounter(0)
--- a/modules/graphics/src/test/java/com/sun/javafx/WeakReferenceMapTest.java	Tue Sep 03 12:13:17 2013 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-/*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.sun.javafx;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-
-import org.junit.Test;
-
-public class WeakReferenceMapTest {
-    @Test
-    public void testAdd() {
-        WeakReferenceMap m = new WeakReferenceMap();
-        String s = new String("Wow!");
-        m.put(s, "value");
-        assertEquals(1, m.size());
-    }
-
-    @Test
-    public void testRemove() {
-        WeakReferenceMap m = new WeakReferenceMap();
-        String a = new String("a");
-        m.put(a, "a-value");
-        String b = new String("b");
-        m.put(b, "b-value");
-        String c = new String("c");
-        m.put(c, "c-value");
-
-        assertEquals(3, m.size());
-        m.remove(a);
-        m.remove(c);
-        assertEquals(1, m.size());
-    }
-
-    @Test
-    public void testCleanup() {
-        WeakReferenceMap m = new WeakReferenceMap();
-        String a = new String("a");
-        m.put(a, "a-value");
-        String b = new String("b");
-        m.put(b, "b-value");
-        String c = new String("c");
-        m.put(c, "c-value");
-
-        assertEquals(3, m.size());
-        a = null;
-        c = null;
-        System.gc();
-        System.gc();
-        System.gc(); // hope that worked!
-        assertEquals(1, m.size());
-    }
-
-    @Test
-    public void testGet() {
-        WeakReferenceMap m = new WeakReferenceMap();
-        String a = new String("a");
-        m.put(a, "a-value");
-        String b = new String("b");
-        m.put(b, "b-value");
-        String c = new String("c");
-        m.put(c, "c-value");
-
-        assertEquals("a-value", m.get(a));
-        assertEquals("b-value", m.get(b));
-        assertEquals("c-value", m.get(c));
-        assertNull(m.get("z"));
-    }
-}
--- a/modules/graphics/src/test/java/com/sun/javafx/sg/prism/NGTestBase.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/test/java/com/sun/javafx/sg/prism/NGTestBase.java	Tue Sep 03 09:40:03 2013 -0700
@@ -101,14 +101,29 @@
         return c;
     }
 
-    public static TestNGEllipse createEllipse(int cx, int cy, int radiusX, int radiusY) {
-        TestNGEllipse e = new TestNGEllipse();
-        e.updateEllipse(cx, cy, radiusX, radiusY);
-        final RectBounds bounds = new RectBounds(cx - radiusX, cy - radiusY, cx + radiusX, cy + radiusY);
-        e.setContentBounds(bounds);
-        e.setTransformMatrix(BaseTransform.IDENTITY_TRANSFORM);
-        e.setTransformedBounds(bounds, false);
-        return e;
+    public static TestNGRegion createOpaqueRegion(int x, int y, int width, int height, NGNode... children) {
+        TestNGRegion r = createTransparentRegion(x, y, width, height, children);
+        r.updateBackground(new Background(new BackgroundFill(javafx.scene.paint.Color.BLACK, null, null)));
+        r.setOpaqueInsets(0, 0, 0, 0);
+        return r;
+    }
+
+    public static TestNGRegion createTransparentRegion(int x, int y, int width, int height, NGNode... children) {
+        TestNGRegion r = new TestNGRegion();
+        for (NGNode child : children) {
+            r.add(-1, child);
+        }
+        r.setSize(width, height);
+        final RectBounds bounds = new RectBounds(0, 0, width, height);
+        r.setContentBounds(bounds);
+        if (x != 0 || y != 0) {
+            r.setTransformMatrix(BaseTransform.getTranslateInstance(x, y));
+            r.setTransformedBounds(r.getTransform().transform(bounds, new RectBounds()), true);
+        } else {
+            r.setTransformMatrix(BaseTransform.IDENTITY_TRANSFORM);
+            r.setTransformedBounds(bounds, false);
+        }
+        return r;
     }
 
     public static TestNGGroup createGroup(NGNode... children) {
@@ -277,32 +292,6 @@
 
     }
 
-    public  static final class TestNGEllipse extends NGEllipse implements TestNGNode {
-        private boolean askedToAccumulateDirtyRegion;
-        private boolean computedDirtyRegion;
-        private boolean rendered;
-
-        @Override
-        protected void renderContent(Graphics g) {
-            rendered = true;
-        }
-
-        @Override public int accumulateDirtyRegions(final RectBounds clip,
-                RectBounds dirtyRegion, DirtyRegionPool pool, DirtyRegionContainer drc, BaseTransform tx, GeneralTransform3D pvTx) {
-            askedToAccumulateDirtyRegion = true;
-            return super.accumulateDirtyRegions(clip, dirtyRegion, pool, drc, tx, pvTx);
-        }
-        @Override protected int accumulateNodeDirtyRegion(
-                final RectBounds clip, RectBounds dirtyRegion, DirtyRegionContainer drc, BaseTransform tx, GeneralTransform3D pvTx)
-        {
-            computedDirtyRegion = true;
-            return super.accumulateNodeDirtyRegion(clip, dirtyRegion, drc,tx, pvTx);
-        }
-        @Override public boolean askedToAccumulateDirtyRegion() { return askedToAccumulateDirtyRegion; }
-        @Override public boolean computedDirtyRegion() { return computedDirtyRegion; }
-        @Override public boolean rendered() { return rendered; }
-    }
-
     public interface TestNGNode {
         public boolean askedToAccumulateDirtyRegion();
         public boolean computedDirtyRegion();
--- a/modules/graphics/src/test/java/com/sun/javafx/sg/prism/OcclusionCullingTest.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/test/java/com/sun/javafx/sg/prism/OcclusionCullingTest.java	Tue Sep 03 09:40:03 2013 -0700
@@ -44,7 +44,7 @@
         final TestNGRectangle root = createRectangle(0, 0, 50, 50);
         TestNGGroup group = createGroup(
                 createRectangle(0, 0, 100, 100), root);
-        NodePath<NGNode> rootPath = new NodePath<>();
+        NodePath rootPath = new NodePath();
         group.getRenderRoot(rootPath, new RectBounds(20, 20, 30, 30), -1, BaseTransform.IDENTITY_TRANSFORM, new GeneralTransform3D());
         TestGraphics g = new TestGraphics();
         g.setRenderRoot(rootPath);
@@ -58,7 +58,7 @@
         final TestNGRectangle root = createRectangle(0, 0, 50, 50);
         TestNGGroup group = createGroup(createGroup(
                 createRectangle(0, 0, 100, 100)), createGroup(root));
-        NodePath<NGNode> rootPath = new NodePath<>();
+        NodePath rootPath = new NodePath();
         group.getRenderRoot(rootPath, new RectBounds(20, 20, 30, 30), -1, BaseTransform.IDENTITY_TRANSFORM, new GeneralTransform3D());
         TestGraphics g = new TestGraphics();
         g.setRenderRoot(rootPath);
@@ -72,7 +72,7 @@
         final TestNGRegion root = createRegion(50, 50);
         TestNGGroup group = createGroup(
                 createRegion(100, 100), root);
-        NodePath<NGNode> rootPath = new NodePath<>();
+        NodePath rootPath = new NodePath();
         group.getRenderRoot(rootPath, new RectBounds(20, 20, 30, 30), -1, BaseTransform.IDENTITY_TRANSFORM, new GeneralTransform3D());
         TestGraphics g = new TestGraphics();
         g.setRenderRoot(rootPath);
@@ -88,7 +88,7 @@
         TestNGGroup group = createGroup(
                 root, other);
         other.setOpaqueInsets(30, 30, 0, 0);
-        NodePath<NGNode> rootPath = new NodePath<>();
+        NodePath rootPath = new NodePath();
         group.getRenderRoot(rootPath, new RectBounds(20, 20, 30, 30), -1, BaseTransform.IDENTITY_TRANSFORM, new GeneralTransform3D());
         TestGraphics g = new TestGraphics();
         g.setRenderRoot(rootPath);
@@ -103,7 +103,7 @@
         TestNGGroup group = createGroup(
                 createGroup(createRectangle(10, 10, 100, 100), createRectangle(20, 20, 20, 20)),
                 createGroup(root));
-        NodePath<NGNode> rootPath = new NodePath<>();
+        NodePath rootPath = new NodePath();
         group.getRenderRoot(rootPath, new RectBounds(10, 10, 100, 100), -1, BaseTransform.IDENTITY_TRANSFORM, new GeneralTransform3D());
         TestGraphics g = new TestGraphics();
         g.setRenderRoot(rootPath);
@@ -124,18 +124,64 @@
         rootParent.childDirty = false;
         root.dirty = NGNode.DirtyFlag.CLEAN;
         root.childDirty = false;
-        NodePath<NGNode> rootPath = new NodePath<>();
+        NodePath rootPath = new NodePath();
         group.getRenderRoot(rootPath, new RectBounds(10, 10, 100, 100), -1, BaseTransform.IDENTITY_TRANSFORM, new GeneralTransform3D());
         assertTrue(rootPath.isEmpty());
 
         final TestNGRectangle dirtySibling = createRectangle(0,0,10,10);
-        rootParent.add(-1,dirtySibling);
-        rootPath = new NodePath<>();
+        rootParent.add(-1, dirtySibling);
+        rootPath = new NodePath();
         group.getRenderRoot(rootPath, new RectBounds(10, 10, 100, 100), -1, BaseTransform.IDENTITY_TRANSFORM, new GeneralTransform3D());
-        assertRoot(rootPath, rootParent);
+        assertRoot(rootPath, root);
     }
 
-    private void checkRootRendering(TestNGNode node, NodePath<NGNode> root) {
+    @Test
+    public void testTransparentRegionWithChildren() {
+        final TestNGRectangle root = createRectangle(10, 10, 100, 100);
+        final TestNGGroup rootParent = createGroup(root);
+        TestNGRegion region = createTransparentRegion(0, 0, 100, 100,
+                createGroup(createRectangle(10, 10, 100, 100), createRectangle(20, 20, 20, 20)), rootParent);
+
+        region.dirty =  NGNode.DirtyFlag.CLEAN; // need to clean default dirty flags
+        rootParent.dirty = NGNode.DirtyFlag.CLEAN;
+        rootParent.childDirty = false;
+        root.dirty = NGNode.DirtyFlag.CLEAN;
+        root.childDirty = false;
+        NodePath rootPath = new NodePath();
+        region.getRenderRoot(rootPath, new RectBounds(10, 10, 100, 100), -1, BaseTransform.IDENTITY_TRANSFORM, new GeneralTransform3D());
+        assertTrue(rootPath.isEmpty());
+
+        final TestNGRectangle dirtySibling = createRectangle(0,0,10,10);
+        rootParent.add(-1,dirtySibling);
+        rootPath = new NodePath();
+        region.getRenderRoot(rootPath, new RectBounds(10, 10, 100, 100), -1, BaseTransform.IDENTITY_TRANSFORM, new GeneralTransform3D());
+        assertRoot(rootPath, root);
+    }
+
+    @Test
+    public void testOpaqueRegion() {
+        final TestNGRectangle rect = createRectangle(10, 10, 100, 100);
+        TestNGRegion region = createOpaqueRegion(0, 0, 200, 200, rect);
+        TestNGGroup root = createGroup(region);
+
+        NodePath rootPath = new NodePath();
+        root.getRenderRoot(rootPath, new RectBounds(10, 10, 100, 100), -1, BaseTransform.IDENTITY_TRANSFORM, new GeneralTransform3D());
+        assertRoot(rootPath, rect);
+
+        rootPath.clear();
+        root.getRenderRoot(rootPath, new RectBounds(5, 5, 150, 150), -1, BaseTransform.IDENTITY_TRANSFORM, new GeneralTransform3D());
+        assertRoot(rootPath, region);
+        TestGraphics g = new TestGraphics();
+        g.setRenderRoot(rootPath);
+        root.render(g);
+        checkRootRendering(root, rootPath);
+
+        rootPath.clear();
+        root.getRenderRoot(rootPath, new RectBounds(-5, -5, 150, 150), -1, BaseTransform.IDENTITY_TRANSFORM, new GeneralTransform3D());
+        assertRoot(rootPath, root);
+    }
+
+    private void checkRootRendering(TestNGNode node, NodePath root) {
         assertTrue(node.rendered());
         if (node instanceof TestNGGroup) {
             if (root.hasNext()) {
@@ -167,7 +213,7 @@
         }
     }
 
-    private void assertRoot(NodePath<NGNode> rootPath, final NGNode root) {
+    private void assertRoot(NodePath rootPath, final NGNode root) {
         rootPath.reset();
         while(rootPath.hasNext()) {
             rootPath.next();
--- a/modules/graphics/src/test/java/com/sun/javafx/sg/prism/RenderRootTest.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/test/java/com/sun/javafx/sg/prism/RenderRootTest.java	Tue Sep 03 09:40:03 2013 -0700
@@ -76,14 +76,14 @@
      * @param dirtyHeight The height of the dirty region
      * @return The NodePath, or null if there are no path elements
      */
-    private NodePath<NGNode> getRenderRoot(NGGroup root, int dirtyX, int dirtyY, int dirtyWidth, int dirtyHeight) {
+    private NodePath getRenderRoot(NGGroup root, int dirtyX, int dirtyY, int dirtyWidth, int dirtyHeight) {
         final DirtyRegionContainer drc = new DirtyRegionContainer(1);
         final RectBounds dirtyRegion = new RectBounds(dirtyX, dirtyY, dirtyX+dirtyWidth, dirtyY+dirtyHeight);
         drc.addDirtyRegion(dirtyRegion);
         final BaseTransform tx = BaseTransform.IDENTITY_TRANSFORM;
         final GeneralTransform3D pvTx = new GeneralTransform3D();
         root.markCullRegions(drc, -1, tx, pvTx);
-        NodePath<NGNode> path = new NodePath<>();
+        NodePath path = new NodePath();
         root.getRenderRoot(path, dirtyRegion, 0, tx, pvTx);
         return path;
     }
@@ -106,7 +106,7 @@
      * never be null). If expectedRoot is null, rootPath must be empty. Otherwise,
      * expectedRoot must be the last item in rootPath.
      */
-    private void assertRenderRoot(NGNode expectedRoot, NodePath<NGNode> rootPath) {
+    private void assertRenderRoot(NGNode expectedRoot, NodePath rootPath) {
         if (expectedRoot == null) {
             assertTrue(rootPath.isEmpty());
         } else {
@@ -122,7 +122,7 @@
      */
     @Test
     public void dirtyRegionWithinOpaqueRegion() {
-        NodePath<NGNode> rootPath = getRenderRoot(root, 20, 20, 70, 70);
+        NodePath rootPath = getRenderRoot(root, 20, 20, 70, 70);
         assertRenderRoot(rect, rootPath);
     }
 
@@ -133,7 +133,7 @@
     @Test
     public void dirtyRegionWithinOpaqueRegion_Clean() {
         root.clearDirtyTree();
-        NodePath<NGNode> rootPath = getRenderRoot(root, 20, 20, 70, 70);
+        NodePath rootPath = getRenderRoot(root, 20, 20, 70, 70);
         assertRenderRoot(null, rootPath);
     }
 
@@ -143,7 +143,7 @@
      */
     @Test
     public void dirtyRegionMatchesOpaqueRegion() {
-        NodePath<NGNode> rootPath = getRenderRoot(root, 10, 10, 90, 90);
+        NodePath rootPath = getRenderRoot(root, 10, 10, 90, 90);
         assertRenderRoot(rect, rootPath);
     }
 
@@ -154,7 +154,7 @@
     @Test
     public void dirtyRegionMatchesOpaqueRegion_Clean() {
         root.clearDirtyTree();
-        NodePath<NGNode> rootPath = getRenderRoot(root, 10, 10, 90, 90);
+        NodePath rootPath = getRenderRoot(root, 10, 10, 90, 90);
         assertRenderRoot(null, rootPath);
     }
 
@@ -164,7 +164,7 @@
      */
     @Test
     public void dirtyRegionWithinOpaqueRegionTouchesTop() {
-        NodePath<NGNode> rootPath = getRenderRoot(root, 20, 10, 70, 70);
+        NodePath rootPath = getRenderRoot(root, 20, 10, 70, 70);
         assertRenderRoot(rect, rootPath);
     }
 
@@ -175,7 +175,7 @@
     @Test
     public void dirtyRegionWithinOpaqueRegionTouchesTop_Clean() {
         root.clearDirtyTree();
-        NodePath<NGNode> rootPath = getRenderRoot(root, 20, 10, 70, 70);
+        NodePath rootPath = getRenderRoot(root, 20, 10, 70, 70);
         assertRenderRoot(null, rootPath);
     }
 
@@ -185,7 +185,7 @@
      */
     @Test
     public void dirtyRegionWithinOpaqueRegionTouchesRight() {
-        NodePath<NGNode> rootPath = getRenderRoot(root, 20, 20, 80, 70);
+        NodePath rootPath = getRenderRoot(root, 20, 20, 80, 70);
         assertRenderRoot(rect, rootPath);
     }
     /**
@@ -195,7 +195,7 @@
     @Test
     public void dirtyRegionWithinOpaqueRegionTouchesRight_Clean() {
         root.clearDirtyTree();
-        NodePath<NGNode> rootPath = getRenderRoot(root, 20, 20, 80, 70);
+        NodePath rootPath = getRenderRoot(root, 20, 20, 80, 70);
         assertRenderRoot(null, rootPath);
     }
 
@@ -205,7 +205,7 @@
      */
     @Test
     public void dirtyRegionWithinOpaqueRegionTouchesBottom() {
-        NodePath<NGNode> rootPath = getRenderRoot(root, 20, 20, 70, 80);
+        NodePath rootPath = getRenderRoot(root, 20, 20, 70, 80);
         assertRenderRoot(rect, rootPath);
     }
 
@@ -216,7 +216,7 @@
     @Test
     public void dirtyRegionWithinOpaqueRegionTouchesBottom_Clean() {
         root.clearDirtyTree();
-        NodePath<NGNode> rootPath = getRenderRoot(root, 20, 20, 70, 80);
+        NodePath rootPath = getRenderRoot(root, 20, 20, 70, 80);
         assertRenderRoot(null, rootPath);
     }
 
@@ -226,7 +226,7 @@
      */
     @Test
     public void dirtyRegionWithinOpaqueRegionTouchesLeft() {
-        NodePath<NGNode> rootPath = getRenderRoot(root, 10, 20, 70, 70);
+        NodePath rootPath = getRenderRoot(root, 10, 20, 70, 70);
         assertRenderRoot(rect, rootPath);
     }
 
@@ -237,99 +237,99 @@
     @Test
     public void dirtyRegionWithinOpaqueRegionTouchesLeft_Clean() {
         root.clearDirtyTree();
-        NodePath<NGNode> rootPath = getRenderRoot(root, 10, 20, 70, 70);
+        NodePath rootPath = getRenderRoot(root, 10, 20, 70, 70);
         assertRenderRoot(null, rootPath);
     }
 
     @Test
     public void opaqueRegionWithinDirtyRegion() {
-        NodePath<NGNode> rootPath = getRenderRoot(root, 0, 0, 110, 110);
+        NodePath rootPath = getRenderRoot(root, 0, 0, 110, 110);
         assertRenderRoot(root, rootPath);
     }
 
     @Test
     public void opaqueRegionWithinDirtyRegion_Clean() {
         root.clearDirtyTree();
-        NodePath<NGNode> rootPath = getRenderRoot(root, 0, 0, 110, 110);
+        NodePath rootPath = getRenderRoot(root, 0, 0, 110, 110);
         assertRenderRoot(root, rootPath);
     }
 
     @Test
     public void dirtyRegionIntersectsOpaqueRegionTop() {
-        NodePath<NGNode> rootPath = getRenderRoot(root, 20, 0, 70, 30);
+        NodePath rootPath = getRenderRoot(root, 20, 0, 70, 30);
         assertRenderRoot(root, rootPath);
     }
 
     @Test
     public void dirtyRegionIntersectsOpaqueRegionTop_Clean() {
         root.clearDirtyTree();
-        NodePath<NGNode> rootPath = getRenderRoot(root, 20, 0, 70, 30);
+        NodePath rootPath = getRenderRoot(root, 20, 0, 70, 30);
         assertRenderRoot(root, rootPath);
     }
 
     @Test
     public void dirtyRegionIntersectsOpaqueRegionRight() {
-        NodePath<NGNode> rootPath = getRenderRoot(root, 90, 20, 30, 70);
+        NodePath rootPath = getRenderRoot(root, 90, 20, 30, 70);
         assertRenderRoot(root, rootPath);
     }
 
     @Test
     public void dirtyRegionIntersectsOpaqueRegionRight_Clean() {
         root.clearDirtyTree();
-        NodePath<NGNode> rootPath = getRenderRoot(root, 90, 20, 30, 70);
+        NodePath rootPath = getRenderRoot(root, 90, 20, 30, 70);
         assertRenderRoot(root, rootPath);
     }
 
     @Test
     public void dirtyRegionIntersectsOpaqueRegionBottom() {
-        NodePath<NGNode> rootPath = getRenderRoot(root, 20, 90, 70, 30);
+        NodePath rootPath = getRenderRoot(root, 20, 90, 70, 30);
         assertRenderRoot(root, rootPath);
     }
 
     @Test
     public void dirtyRegionIntersectsOpaqueRegionBottom_Clean() {
         root.clearDirtyTree();
-        NodePath<NGNode> rootPath = getRenderRoot(root, 20, 90, 70, 30);
+        NodePath rootPath = getRenderRoot(root, 20, 90, 70, 30);
         assertRenderRoot(root, rootPath);
     }
 
     @Test
     public void dirtyRegionIntersectsOpaqueRegionLeft() {
-        NodePath<NGNode> rootPath = getRenderRoot(root, 0, 20, 30, 70);
+        NodePath rootPath = getRenderRoot(root, 0, 20, 30, 70);
         assertRenderRoot(root, rootPath);
     }
 
     @Test
     public void dirtyRegionIntersectsOpaqueRegionLeft_Clean() {
         root.clearDirtyTree();
-        NodePath<NGNode> rootPath = getRenderRoot(root, 0, 20, 30, 70);
+        NodePath rootPath = getRenderRoot(root, 0, 20, 30, 70);
         assertRenderRoot(root, rootPath);
     }
 
     @Test
     public void dirtyRegionCompletelyOutsideOfOpaqueRegion() {
-        NodePath<NGNode> rootPath = getRenderRoot(root, 0, 0, 5, 5);
+        NodePath rootPath = getRenderRoot(root, 0, 0, 5, 5);
         assertRenderRoot(root, rootPath);
     }
 
     @Test
     public void dirtyRegionCompletelyOutsideOfOpaqueRegion_Clean() {
         root.clearDirtyTree();
-        NodePath<NGNode> rootPath = getRenderRoot(root, 0, 0, 5, 5);
+        NodePath rootPath = getRenderRoot(root, 0, 0, 5, 5);
         assertRenderRoot(root, rootPath);
     }
 
     @Ignore("What is the right thing here? It seems that an empty dirty region should result in no rendering?")
     @Test
     public void emptyDirtyRegion() {
-        NodePath<NGNode> rootPath = getRenderRoot(root, 0, 0, -1, -1);
+        NodePath rootPath = getRenderRoot(root, 0, 0, -1, -1);
         assertRenderRoot(root, rootPath);
     }
 
     @Ignore("Currently fails because isEmpty doesn't take into account width == 0, height == 0")
     @Test
     public void zeroSizeDirtyRegionWithinOpaqueRegion() {
-        NodePath<NGNode> rootPath = getRenderRoot(root, 20, 20, 0, 0);
+        NodePath rootPath = getRenderRoot(root, 20, 20, 0, 0);
         assertRenderRoot(root, rootPath);
     }
 
@@ -342,7 +342,7 @@
     public void withRectangularClip() {
         NGRectangle clip = createRectangle(20, 20, 70, 70);
         rect.setClipNode(clip);
-        NodePath<NGNode> rootPath = getRenderRoot(root, 20, 20, 70, 70);
+        NodePath rootPath = getRenderRoot(root, 20, 20, 70, 70);
         assertRenderRoot(rect, rootPath);
     }
 
@@ -353,7 +353,7 @@
     public void withRectangularClip_negative() {
         NGRectangle clip = createRectangle(20, 20, 70, 70);
         rect.setClipNode(clip);
-        NodePath<NGNode> rootPath = getRenderRoot(root, 19, 20, 70, 70);
+        NodePath rootPath = getRenderRoot(root, 19, 20, 70, 70);
         assertRenderRoot(root, rootPath);
     }
 
@@ -365,7 +365,7 @@
         NGRectangle clip = createRectangle(20, 20, 70, 70);
         clip.setTransformMatrix(BaseTransform.getTranslateInstance(10, 10));
         rect.setClipNode(clip);
-        NodePath<NGNode> rootPath = getRenderRoot(root, 30, 30, 70, 70);
+        NodePath rootPath = getRenderRoot(root, 30, 30, 70, 70);
         assertRenderRoot(rect, rootPath);
     }
 
@@ -377,7 +377,7 @@
         NGRectangle clip = createRectangle(20, 20, 70, 70);
         clip.setTransformMatrix(BaseTransform.getTranslateInstance(10, 10));
         rect.setClipNode(clip);
-        NodePath<NGNode> rootPath = getRenderRoot(root, 29, 30, 70, 70);
+        NodePath rootPath = getRenderRoot(root, 29, 30, 70, 70);
         assertRenderRoot(root, rootPath);
     }
 
@@ -389,7 +389,7 @@
         NGRectangle clip = createRectangle(20, 20, 70, 70);
         clip.setTransformMatrix(BaseTransform.getScaleInstance(.5, .5));
         rect.setClipNode(clip);
-        NodePath<NGNode> rootPath = getRenderRoot(root, 10, 10, 35, 35);
+        NodePath rootPath = getRenderRoot(root, 10, 10, 35, 35);
         assertRenderRoot(rect, rootPath);
     }
 
@@ -401,7 +401,7 @@
         NGRectangle clip = createRectangle(20, 20, 70, 70);
         clip.setTransformMatrix(BaseTransform.getScaleInstance(.5, .5));
         rect.setClipNode(clip);
-        NodePath<NGNode> rootPath = getRenderRoot(root, 9, 10, 35, 35);
+        NodePath rootPath = getRenderRoot(root, 9, 10, 35, 35);
         assertRenderRoot(root, rootPath);
     }
 
@@ -414,7 +414,7 @@
     public void withCircleClip() {
         NGCircle clip = createCircle(50, 50, 45);
         rect.setClipNode(clip);
-        NodePath<NGNode> rootPath = getRenderRoot(root, 40, 40, 20, 20);
+        NodePath rootPath = getRenderRoot(root, 40, 40, 20, 20);
         assertRenderRoot(rect, rootPath);
     }
 
@@ -425,7 +425,7 @@
     public void withCircleClip_negative() {
         NGCircle clip = createCircle(50, 50, 45);
         rect.setClipNode(clip);
-        NodePath<NGNode> rootPath = getRenderRoot(root, 10, 10, 90, 90);
+        NodePath rootPath = getRenderRoot(root, 10, 10, 90, 90);
         assertRenderRoot(root, rootPath);
     }
 }
--- a/modules/graphics/src/test/java/javafx/animation/AnimationTest.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/test/java/javafx/animation/AnimationTest.java	Tue Sep 03 09:40:03 2013 -0700
@@ -43,7 +43,7 @@
 import static org.junit.Assert.*;
 
 public class AnimationTest {
-	
+
     private static final Duration ONE_SEC = Duration.millis(1000);
     private static final Duration TWO_SECS = Duration.millis(2000);
     private static final Duration THREE_SECS = Duration.millis(3000);
@@ -52,7 +52,7 @@
     private static final double DEFAULT_RATE = 1.0;
     private static final int DEFAULT_REPEAT_COUNT = 1;
     private static final boolean DEFAULT_AUTO_REVERSE = false;
-    
+
     private static final double EPSILON = 1e-12;
 
     private AbstractMasterTimerMock timer;
@@ -97,23 +97,23 @@
         // currentRate
         assertEquals("currentRate", animation.currentRateProperty().getName());
         assertEquals(animation, animation.currentRateProperty().getBean());
-        
+
         // cycleDuration
         assertEquals("cycleDuration", animation.cycleDurationProperty().getName());
         assertEquals(animation, animation.cycleDurationProperty().getBean());
-        
+
         // totalDuration
         assertEquals("totalDuration", animation.totalDurationProperty().getName());
         assertEquals(animation, animation.totalDurationProperty().getBean());
-        
+
         // currentTime
         assertEquals("currentTime", animation.currentTimeProperty().getName());
         assertEquals(animation, animation.currentTimeProperty().getBean());
-        
+
         // status
         assertEquals("status", animation.statusProperty().getName());
         assertEquals(animation, animation.statusProperty().getBean());
-        
+
     }
 
     @Test
@@ -441,6 +441,22 @@
     }
 
     @Test
+    public void testChangeCycleDurationAfterFinish_RT32657() {
+        animation.setCycleDuration(TWO_SECS);
+        animation.play();
+        assertEquals(Status.RUNNING, animation.getStatus());
+        assertEquals(Duration.ZERO, animation.getCurrentTime());
+        animation.impl_setCurrentTicks(12000);
+        assertEquals(TWO_SECS, animation.getCurrentTime());
+        animation.impl_finished();
+
+        animation.setCycleDuration(ONE_SEC);
+        animation.play();
+        assertEquals(Status.RUNNING, animation.getStatus());
+        assertEquals(Duration.ZERO, animation.getCurrentTime());
+    }
+
+    @Test
     public void testFinished() {
         final OnFinishedListener listener = new OnFinishedListener();
         animation.setOnFinished(listener);
--- a/modules/graphics/src/test/java/javafx/scene/layout/BackgroundTest.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/graphics/src/test/java/javafx/scene/layout/BackgroundTest.java	Tue Sep 03 09:40:03 2013 -0700
@@ -639,6 +639,75 @@
         assertEquals(22.5, trbl[3], 0); // bottom-left-horizontal dominates at 22.5
     }
 
+    @Test public void backgroundFillsArePercentageBased_AllPercentageBased() {
+        BackgroundFill f = new BackgroundFill(Color.RED, new CornerRadii(.5, true), new Insets(10, 0, 0, 0));
+        BackgroundFill f2 = new BackgroundFill(Color.GREEN, new CornerRadii(.4, true), new Insets(0, 10, 0, 0));
+        BackgroundFill f3 = new BackgroundFill(Color.BLUE, new CornerRadii(.3, true), new Insets(0, 0, 10, 0));
+        BackgroundFill f4 = new BackgroundFill(Color.YELLOW, new CornerRadii(.2, true), new Insets(0, 0, 0, 10));
+        Background b = new Background(new BackgroundFill[] { f, f2, f3, f4 }, null);
+        assertTrue(b.isFillPercentageBased());
+    }
+
+    @Test public void backgroundFillsArePercentageBased_OnePercentageBased() {
+        BackgroundFill f = new BackgroundFill(Color.RED, new CornerRadii(5), new Insets(10, 0, 0, 0));
+        BackgroundFill f2 = new BackgroundFill(Color.GREEN, new CornerRadii(4), new Insets(0, 10, 0, 0));
+        BackgroundFill f3 = new BackgroundFill(Color.BLUE, new CornerRadii(.3, true), new Insets(0, 0, 10, 0));
+        BackgroundFill f4 = new BackgroundFill(Color.YELLOW, new CornerRadii(2), new Insets(0, 0, 0, 10));
+        Background b = new Background(new BackgroundFill[] { f, f2, f3, f4 }, null);
+        assertTrue(b.isFillPercentageBased());
+    }
+
+    @Test public void backgroundFillsArePercentageBased_OneCornerOfOne() {
+        BackgroundFill f = new BackgroundFill(Color.RED, new CornerRadii(5, 5, .5, 5, 5, 5, 5, 5,
+                false, false, true, false, false, false, false, false), new Insets(10, 0, 0, 0));
+        BackgroundFill f2 = new BackgroundFill(Color.GREEN, new CornerRadii(4), new Insets(0, 10, 0, 0));
+        BackgroundFill f3 = new BackgroundFill(Color.BLUE, new CornerRadii(3), new Insets(0, 0, 10, 0));
+        BackgroundFill f4 = new BackgroundFill(Color.YELLOW, new CornerRadii(2), new Insets(0, 0, 0, 10));
+        Background b = new Background(new BackgroundFill[] { f, f2, f3, f4 }, null);
+        assertTrue(b.isFillPercentageBased());
+    }
+
+    @Test public void backgroundFillsAreNotPercentageBased() {
+        BackgroundFill f = new BackgroundFill(Color.RED, new CornerRadii(5), new Insets(10, 0, 0, 0));
+        BackgroundFill f2 = new BackgroundFill(Color.GREEN, new CornerRadii(4), new Insets(0, 10, 0, 0));
+        BackgroundFill f3 = new BackgroundFill(Color.BLUE, new CornerRadii(3), new Insets(0, 0, 10, 0));
+        BackgroundFill f4 = new BackgroundFill(Color.YELLOW, new CornerRadii(2), new Insets(0, 0, 0, 10));
+        Background b = new Background(new BackgroundFill[] { f, f2, f3, f4 }, null);
+        assertFalse(b.isFillPercentageBased());
+    }
+
+    @Test public void backgroundFillsAreNotPercentageBased_NoFills() {
+        Background b = new Background(new BackgroundFill[0]);
+        assertFalse(b.isFillPercentageBased());
+    }
+
+    @Test public void backgroundFillsAreNotPercentageBased_NullRadii() {
+        BackgroundFill f = new BackgroundFill(Color.RED, null, new Insets(10, 0, 0, 0));
+        BackgroundFill f2 = new BackgroundFill(Color.GREEN, null, new Insets(0, 10, 0, 0));
+        BackgroundFill f3 = new BackgroundFill(Color.BLUE, null, new Insets(0, 0, 10, 0));
+        BackgroundFill f4 = new BackgroundFill(Color.YELLOW, null, new Insets(0, 0, 0, 10));
+        Background b = new Background(new BackgroundFill[] { f, f2, f3, f4 }, null);
+        assertFalse(b.isFillPercentageBased());
+    }
+
+    @Test public void backgroundFillsAreNotPercentageBased_OneEmpty() {
+        BackgroundFill f = new BackgroundFill(Color.RED, CornerRadii.EMPTY, new Insets(10, 0, 0, 0));
+        BackgroundFill f2 = new BackgroundFill(Color.GREEN, new CornerRadii(4), new Insets(0, 10, 0, 0));
+        BackgroundFill f3 = new BackgroundFill(Color.BLUE, new CornerRadii(3), new Insets(0, 0, 10, 0));
+        BackgroundFill f4 = new BackgroundFill(Color.YELLOW, new CornerRadii(2), new Insets(0, 0, 0, 10));
+        Background b = new Background(new BackgroundFill[] { f, f2, f3, f4 }, null);
+        assertFalse(b.isFillPercentageBased());
+    }
+
+    @Test public void backgroundFillsAreNotPercentageBased_AllEmpty() {
+        BackgroundFill f = new BackgroundFill(Color.RED, CornerRadii.EMPTY, new Insets(10, 0, 0, 0));
+        BackgroundFill f2 = new BackgroundFill(Color.GREEN, CornerRadii.EMPTY, new Insets(0, 10, 0, 0));
+        BackgroundFill f3 = new BackgroundFill(Color.BLUE, CornerRadii.EMPTY, new Insets(0, 0, 10, 0));
+        BackgroundFill f4 = new BackgroundFill(Color.YELLOW, CornerRadii.EMPTY, new Insets(0, 0, 0, 10));
+        Background b = new Background(new BackgroundFill[] { f, f2, f3, f4 }, null);
+        assertFalse(b.isFillPercentageBased());
+    }
+
     // TODO: What happens if the corner radii become so big that we would end up with a negative opaque
     // inset in one dimension?
 
--- a/modules/swing/src/main/java/javafx/embed/swing/SwingNode.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/swing/src/main/java/javafx/embed/swing/SwingNode.java	Tue Sep 03 09:40:03 2013 -0700
@@ -75,13 +75,10 @@
  * <pre>
  *     public class SwingFx extends Application {
  *
- *         private SwingNode swingNode;
- *
  *         &#064;Override
  *         public void start(Stage stage) {
- *             swingNode = new SwingNode();
- *
- *             createAndSetSwingContent();
+ *             final SwingNode swingNode = new SwingNode();
+ *             createAndSetSwingContent(swingNode);
  *
  *             StackPane pane = new StackPane();
  *             pane.getChildren().add(swingNode);
@@ -90,7 +87,7 @@
  *             stage.show();
  *         }
  *
- *         private void createAndSetSwingContent() {
+ *         private void createAndSetSwingContent(final SwingNode swingNode) {
  *             SwingUtilities.invokeLater(new Runnable() {
  *                 &#064;Override
  *                 public void run() {
@@ -98,6 +95,10 @@
  *                 }
  *             });
  *         }
+ * 
+ *         public static void main(String[] args) {
+ *             launch(args);
+ *         }
  *     }
  * </pre>
  * @since JavaFX 8.0
@@ -143,9 +144,9 @@
     /**
      * Attaches a {@code JComponent} instance to display in this {@code SwingNode}.
      * <p>
-     * The method can be called either on the JavaFX Application thread or the Swing thread.
-     * Note however, that access to a Swing component must occur from the Swing thread according
-     * to the Swing threading restrictions.
+     * The method can be called either on the JavaFX Application thread or the Event Dispatch thread.
+     * Note however, that access to a Swing component must occur from the Event Dispatch thread
+     * according to the Swing threading restrictions.
      *
      * @param content a Swing component to display in this {@code SwingNode}
      *
@@ -166,9 +167,9 @@
    /**
      * Returns the {@code JComponent} instance attached to this {@code SwingNode}.
      * <p>
-     * The method can be called either on the JavaFX Application thread or the Swing thread.
-     * Note however, that access to a Swing component must occur from the Swing thread according
-     * to the Swing threading restrictions.
+     * The method can be called either on the JavaFX Application thread or the Event Dispatch thread.
+     * Note however, that access to a Swing component must occur from the Event Dispatch thread
+     * according to the Swing threading restrictions.
      *
      * @see java.awt.EventQueue#isDispatchThread()
      * @see javafx.application.Platform#isFxApplicationThread()
@@ -180,7 +181,7 @@
     }
 
     /*
-     * Called on Swing thread
+     * Called on EDT
      */
     private void setContentImpl(JComponent content) {
         if (lwFrame != null) {
@@ -208,18 +209,23 @@
             lwFrame.setContent(new SwingNodeContent(content));
             lwFrame.setVisible(true);
 
-            locateLwFrame(); // initialize location
+            Platform.runLater(new Runnable() {
+                @Override
+                public void run() {
+                    locateLwFrame(); // initialize location
 
-            if (focusedProperty().get()) {
-                activateLwFrame(true);
-            }
+                    if (focusedProperty().get()) {
+                        activateLwFrame(true);
+                    }
+                }
+            });
         }
     }
 
     private List<Runnable> peerRequests = new ArrayList<>();
 
     /*
-     * Called on Swing thread
+     * Called on EDT
      */
     void setImageBuffer(final int[] data,
                         final int x, final int y,
@@ -241,7 +247,7 @@
     }
 
     /*
-     * Called on Swing thread
+     * Called on EDT
      */
     void setImageBounds(final int x, final int y, final int w, final int h) {
         Runnable r = new Runnable() {
@@ -258,7 +264,7 @@
     }
 
     /*
-     * Called on Swing thread
+     * Called on EDT
      */
     void repaintDirtyRegion(final int dirtyX, final int dirtyY, final int dirtyWidth, final int dirtyHeight) {
         Runnable r = new Runnable() {
@@ -461,7 +467,8 @@
     public void impl_updatePeer() {
         super.impl_updatePeer();
 
-        if (impl_isDirty(DirtyBits.NODE_VISIBLE)) {
+        if (impl_isDirty(DirtyBits.NODE_VISIBLE)
+                || impl_isDirty(DirtyBits.NODE_BOUNDS)) {
             locateLwFrame(); // initialize location
         }
         if (impl_isDirty(DirtyBits.NODE_CONTENTS)) {
@@ -470,7 +477,11 @@
     }
 
     private void locateLwFrame() {
-        if (getScene() == null || lwFrame == null) {
+        if (getScene() == null
+                || lwFrame == null
+                || getScene().getWindow() == null
+                || !getScene().getWindow().isShowing()) {
+            // Not initialized yet. Skip the update to set the real values later
             return;
         }
         final Point2D loc = localToScene(0, 0);
--- a/modules/swt/src/main/java/javafx/embed/swt/FXCanvas.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/swt/src/main/java/javafx/embed/swt/FXCanvas.java	Tue Sep 03 09:40:03 2013 -0700
@@ -27,9 +27,9 @@
 
 import java.lang.reflect.Field;
 import java.nio.IntBuffer;
-
 import java.security.AccessController;
 import java.security.PrivilegedAction;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
@@ -80,7 +80,6 @@
 import org.eclipse.swt.events.MouseMoveListener;
 import org.eclipse.swt.events.PaintEvent;
 import org.eclipse.swt.events.PaintListener;
-
 import org.eclipse.swt.widgets.Canvas;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Display;
@@ -90,7 +89,6 @@
 import org.eclipse.swt.graphics.PaletteData;
 import org.eclipse.swt.graphics.Point;
 import org.eclipse.swt.graphics.Rectangle;
-
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.events.ControlListener;
 import org.eclipse.swt.events.FocusListener;
@@ -151,6 +149,8 @@
     
     private IntBuffer pixelsBuf = null;
     
+    private DropTarget dropTarget;
+    
     static Transfer [] StandardTransfers = new Transfer [] {
         TextTransfer.getInstance(),
         RTFTransfer.getInstance(),
@@ -229,6 +229,39 @@
         });
     }
     
+    static ArrayList<DropTarget> targets = new ArrayList<>();
+    
+    DropTarget getDropTarget() {
+        return dropTarget;
+    }
+    
+    void setDropTarget(DropTarget newTarget) {
+        if (dropTarget != null) {
+            targets.remove(dropTarget);
+            dropTarget.dispose();
+        }
+        dropTarget = newTarget;
+        if (dropTarget != null) {
+            targets.add(dropTarget);
+        }
+    }
+    
+    static void updateDropTarget() {
+        // Update all drop targets rather than just this target
+        //
+        // In order for a drop target to recognise a custom format,
+        // the format must be registered and the transfer type added
+        // to the list of transfers that the target accepts.  This
+        // must happen before the drag and drop operations starts
+        // or the drop target will not accept the format.  Therefore,
+        // set all transfers for all targets before any drag and drop
+        // operation starts
+        //
+        for (DropTarget target : targets) {
+            target.setTransfer(getAllTransfers());
+        }
+    }
+
     /**
      * {@inheritDoc}
      */
@@ -386,6 +419,7 @@
     }
 
     private void widgetDisposed(DisposeEvent de) {
+        setDropTarget(null);
         if (stage != null) {
             stage.hide();
         }
@@ -711,7 +745,12 @@
             dropTarget.setTransfer(getAllTransfers());
             dropTarget.addDropListener(new DropTargetListener() {
                 Object data;
-                TransferData [] transferData;
+                // In SWT, the list of available types that the source can provide
+                // is part of the event.  FX queries this directly from the operating
+                // system and bypasses SWT.  This variable is commented out to remind
+                // us of this potential inconsistency.
+                //
+                //TransferData [] transferData;
                 TransferData currentTransferData;
                 boolean ignoreLeave;
                 int detail = DND.DROP_NONE, operations = DND.DROP_NONE;
@@ -736,7 +775,7 @@
                     }
                     public void dragDropEnd(TransferMode performedAction) {
                         data = null;
-                        transferData = null;
+                        //transferData = null;
                         currentTransferData = null;
                     }
                 };
@@ -749,7 +788,7 @@
                 public void dragLeave(DropTargetEvent event) {
                     detail = operations = DND.DROP_NONE;
                     data = null;
-                    transferData = null;
+                    //transferData = null;
                     currentTransferData = null;
                     getDisplay().asyncExec(new Runnable () {
                         public void run () {
@@ -768,7 +807,7 @@
                     dragOver (event, false, detail);
                 }
                 public void dragOver(DropTargetEvent event, boolean enter, int detail) {
-                    transferData = event.dataTypes;
+                    //transferData = event.dataTypes;
                     currentTransferData = event.currentDataType;
                     Point pt = toControl(event.x, event.y);
                     if (detail == DND.DROP_NONE) detail = DND.DROP_COPY;
@@ -784,14 +823,14 @@
                     detail = event.detail;
                     operations = event.operations;
                     data = event.data;
-                    transferData = event.dataTypes;
+                    //transferData = event.dataTypes;
                     currentTransferData = event.currentDataType;
                     Point pt = toControl(event.x, event.y);
                     TransferMode recommendedDropAction = getTransferMode(event.detail);
                     TransferMode acceptedMode = fxDropTarget.handleDragDrop(pt.x, pt.y, event.x, event.y, recommendedDropAction);
                     event.detail = getDragAction(acceptedMode);
                     data = null;
-                    transferData = null;
+                    //transferData = null;
                     currentTransferData = null;
                 }
                 public void dropAccept(DropTargetEvent event) {
@@ -801,7 +840,6 @@
             return dropTarget;
         }
 
-        DropTarget dropTarget;
         @Override
         public void setEmbeddedScene(EmbeddedSceneInterface embeddedScene) {
             scenePeer = embeddedScene;
@@ -820,15 +858,14 @@
                             if (dragSource == null) {
                                 fxDragSource.dragDropEnd(null);
                             } else {
-                                if (dropTarget != null) dropTarget.setTransfer(getAllTransfers());
+                                updateDropTarget();
                                 FXCanvas.this.notifyListeners(SWT.DragDetect, null);
                             }
                         }
                     });
                 }
             });
-            if (dropTarget != null) dropTarget.dispose();
-            dropTarget = createDropTarget(embeddedScene);
+            setDropTarget(createDropTarget(embeddedScene));
         }
 
         @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/web/src/main/java/com/sun/webkit/WatchdogTimer.java	Tue Sep 03 09:40:03 2013 -0700
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ */
+package com.sun.webkit;
+
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import static java.util.logging.Level.WARNING;
+import java.util.logging.Logger;
+
+final class WatchdogTimer {
+
+    private static final Logger logger =
+            Logger.getLogger(WatchdogTimer.class.getName());
+    private static final ThreadFactory threadFactory =
+            new CustomThreadFactory();
+
+
+    // The executor is intentionally made a non-static/instance
+    // field (as opposed to a static/class field) in order for
+    // fwkDestroy() to be able to orderly shutdown the executor
+    // and wait for the outstanding runnable, if any, to complete.
+    // Currently, there is just a single instance of this class
+    // per process, so having a non-static executor should not
+    // be a problem.
+    private final ScheduledThreadPoolExecutor executor;
+    private final Runnable runnable;
+    private ScheduledFuture<?> future;
+
+
+    private WatchdogTimer(final long nativePointer) {
+        executor = new ScheduledThreadPoolExecutor(1, threadFactory);
+        executor.setRemoveOnCancelPolicy(true);
+
+        runnable = new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    twkFire(nativePointer);
+                } catch (Throwable th) {
+                    logger.log(WARNING, "Error firing watchdog timer", th);
+                }
+            }
+        };
+    }
+
+
+    private static WatchdogTimer fwkCreate(long nativePointer) {
+        return new WatchdogTimer(nativePointer);
+    }
+
+    private void fwkStart(double limit) {
+        if (future != null) {
+            throw new IllegalStateException();
+        }
+        future = executor.schedule(runnable, (long) (limit * 1000) + 50,
+                TimeUnit.MILLISECONDS);
+    }
+
+    private void fwkStop() {
+        if (future == null) {
+            throw new IllegalStateException();
+        }
+        future.cancel(false);
+        future = null;
+    }
+
+    private void fwkDestroy() {
+        executor.shutdownNow();
+        while (true) {
+            try {
+                if (executor.awaitTermination(1, TimeUnit.SECONDS)) {
+                    break;
+                }
+            } catch (InterruptedException ex) {
+                // continue waiting
+            }
+        }
+    }
+
+    private native void twkFire(long nativePointer);
+
+    private static final class CustomThreadFactory implements ThreadFactory {
+        private final ThreadGroup group;
+        private final AtomicInteger index = new AtomicInteger(1);
+
+        private CustomThreadFactory() {
+            SecurityManager s = System.getSecurityManager();
+            group = (s != null) ? s.getThreadGroup()
+                    : Thread.currentThread().getThreadGroup();
+        }
+
+        @Override
+        public Thread newThread(Runnable r) {
+            Thread t = new Thread(group, r,
+                    "Watchdog-Timer-" + index.getAndIncrement());
+            t.setDaemon(true);
+            return t;
+        }
+    }
+}
--- a/modules/web/src/main/native/Source/JavaScriptCore/TargetJava.pri	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/web/src/main/native/Source/JavaScriptCore/TargetJava.pri	Tue Sep 03 09:40:03 2013 -0700
@@ -331,7 +331,7 @@
     runtime/StructureRareData.cpp \
     runtime/SymbolTable.cpp \
     runtime/Watchdog.cpp \
-    runtime/WatchdogNone.cpp \
+    runtime/WatchdogJava.cpp \
     tools/CodeProfile.cpp \
     tools/CodeProfiling.cpp \
     yarr/YarrJIT.cpp \
--- a/modules/web/src/main/native/Source/JavaScriptCore/runtime/Watchdog.cpp	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/web/src/main/native/Source/JavaScriptCore/runtime/Watchdog.cpp	Tue Sep 03 09:40:03 2013 -0700
@@ -95,6 +95,15 @@
     if (!m_timerDidFire)
         return false;
     m_timerDidFire = false;
+
+#if PLATFORM(JAVA)
+    if (m_isStopped) {
+        // If the timer is stopped, it is not counting and m_startTime
+        // is junk so it does not make any sense to proceed
+        return false;
+    }
+#endif
+
     stopCountdown();
 
     double currentTime = currentCPUTime();
@@ -150,8 +159,18 @@
 void Watchdog::disarm()
 {
     ASSERT(m_reentryCount > 0);
+#if PLATFORM(JAVA)
+    if (m_reentryCount == 1) {
+        stopCountdown();
+        // Now that the timer is going out of scope the m_didFire
+        // flag needs to be reset as otherwise the timer would
+        // remain "fired" forever
+        m_didFire = false;
+    }
+#else
     if (m_reentryCount == 1)
         stopCountdown();
+#endif
     m_reentryCount--;
 }
 
--- a/modules/web/src/main/native/Source/JavaScriptCore/runtime/Watchdog.h	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/web/src/main/native/Source/JavaScriptCore/runtime/Watchdog.h	Tue Sep 03 09:40:03 2013 -0700
@@ -30,6 +30,10 @@
 #include <dispatch/dispatch.h>    
 #endif
 
+#if PLATFORM(JAVA)
+#include <wtf/java/JavaRef.h>
+#endif
+
 namespace JSC {
 
 class ExecState;
@@ -98,6 +102,10 @@
     dispatch_source_t m_timer;
 #endif
 
+#if PLATFORM(JAVA)
+    JGObject m_timer;
+#endif
+
     friend class Watchdog::Scope;
     friend class LLIntOffsetsExtractor;
 };
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/web/src/main/native/Source/JavaScriptCore/runtime/WatchdogJava.cpp	Tue Sep 03 09:40:03 2013 -0700
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include "config.h"
+#include "Watchdog.h"
+
+#include "com_sun_webkit_WatchdogTimer.h"
+
+namespace JSC {
+
+static jclass GetWatchdogTimerClass(JNIEnv* env)
+{
+    static JGClass clazz(env->FindClass(
+            "com/sun/webkit/WatchdogTimer"));
+    ASSERT(clazz);
+    return clazz;
+}
+
+void Watchdog::initTimer()
+{
+    JNIEnv* env = JavaScriptCore_GetJavaEnv();
+
+    static jmethodID mid = env->GetStaticMethodID(
+            GetWatchdogTimerClass(env),
+            "fwkCreate",
+            "(J)Lcom/sun/webkit/WatchdogTimer;");
+    ASSERT(mid);
+
+    m_timer = JLObject(env->CallStaticObjectMethod(
+            GetWatchdogTimerClass(env),
+            mid,
+            ptr_to_jlong(timerDidFireAddress())));
+    CheckAndClearException(env);
+}
+
+void Watchdog::destroyTimer()
+{
+    JNIEnv* env = JavaScriptCore_GetJavaEnv();
+
+    static jmethodID mid = env->GetMethodID(
+            GetWatchdogTimerClass(env),
+            "fwkDestroy",
+            "()V");
+    ASSERT(mid);
+
+    env->CallVoidMethod(m_timer, mid);
+    CheckAndClearException(env);
+
+    m_timer.clear();
+}
+
+void Watchdog::startTimer(double limit)
+{
+    JNIEnv* env = JavaScriptCore_GetJavaEnv();
+
+    static jmethodID mid = env->GetMethodID(
+            GetWatchdogTimerClass(env),
+            "fwkStart",
+            "(D)V");
+    ASSERT(mid);
+
+    env->CallVoidMethod(m_timer, mid, (jdouble) limit);
+    CheckAndClearException(env);
+}
+
+void Watchdog::stopTimer()
+{
+    JNIEnv* env = JavaScriptCore_GetJavaEnv();
+
+    static jmethodID mid = env->GetMethodID(
+            GetWatchdogTimerClass(env),
+            "fwkStop",
+            "()V");
+    ASSERT(mid);
+
+    env->CallVoidMethod(m_timer, mid);
+    CheckAndClearException(env);
+}
+
+} // namespace JSC
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+JNIEXPORT void JNICALL Java_com_sun_webkit_WatchdogTimer_twkFire
+  (JNIEnv*, jobject, jlong nativePointer)
+{
+    bool* timerDidFireAddress = static_cast<bool*>(jlong_to_ptr(nativePointer));
+    ASSERT(timerDidFireAddress);
+    *timerDidFireAddress = true;
+}
+
+#ifdef __cplusplus
+}
+#endif
--- a/modules/web/src/main/native/Source/WebCore/mapfile-macosx	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/web/src/main/native/Source/WebCore/mapfile-macosx	Tue Sep 03 09:40:03 2013 -0700
@@ -1836,6 +1836,7 @@
                _Java_com_sun_webkit_WCPluginWidget_twkInvalidateWindowlessPluginRect
                _Java_com_sun_webkit_WCPluginWidget_twkSetPlugunFocused
                _Java_com_sun_webkit_WCWidget_initIDs
+               _Java_com_sun_webkit_WatchdogTimer_twkFire
                _Java_com_sun_webkit_WebPage_twkAddJavaScriptBinding
                _Java_com_sun_webkit_WebPage_twkAdjustFrameHeight
                _Java_com_sun_webkit_WebPage_twkBeginPrinting
--- a/modules/web/src/main/native/Source/WebCore/mapfile-vers	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/web/src/main/native/Source/WebCore/mapfile-vers	Tue Sep 03 09:40:03 2013 -0700
@@ -1836,6 +1836,7 @@
                Java_com_sun_webkit_WCPluginWidget_twkInvalidateWindowlessPluginRect;
                Java_com_sun_webkit_WCPluginWidget_twkSetPlugunFocused;
                Java_com_sun_webkit_WCWidget_initIDs;
+               Java_com_sun_webkit_WatchdogTimer_twkFire;
                Java_com_sun_webkit_WebPage_twkAddJavaScriptBinding;
                Java_com_sun_webkit_WebPage_twkAdjustFrameHeight;
                Java_com_sun_webkit_WebPage_twkBeginPrinting;
--- a/modules/web/src/main/native/Source/WebCore/platform/java/WebPage.cpp	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/web/src/main/native/Source/WebCore/platform/java/WebPage.cpp	Tue Sep 03 09:40:03 2013 -0700
@@ -38,6 +38,7 @@
 #include "InspectorClientJava.h"
 #include "InspectorController.h"
 #include "InitializeLogging.h"
+#include "JSContextRefPrivate.h"
 #include "JavaEnv.h"
 #include "JavaRef.h"
 #include "Logging.h"
@@ -816,6 +817,10 @@
     frameLoaderClient->setFrame(frame.get());
 
     frame->init();
+
+    JSGlobalContextRef globalContext = getGlobalContext(frame->script());
+    JSContextGroupRef contextGroup = JSContextGetGroup(globalContext);
+    JSContextGroupSetExecutionTimeLimit(contextGroup, 10, 0, 0);
 }
 
 JNIEXPORT void JNICALL Java_com_sun_webkit_WebPage_twkDestroyPage
--- a/modules/web/src/test/java/javafx/scene/web/IrresponsiveScriptTest.java	Tue Sep 03 12:13:17 2013 -0400
+++ b/modules/web/src/test/java/javafx/scene/web/IrresponsiveScriptTest.java	Tue Sep 03 09:40:03 2013 -0700
@@ -3,16 +3,15 @@
  */
 package javafx.scene.web;
 
-import java.util.concurrent.atomic.AtomicBoolean;
+import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadMXBean;
 import javafx.event.EventHandler;
 import netscape.javascript.JSException;
 import org.junit.Test;
-import static org.junit.Assert.*;
-
 
 public class IrresponsiveScriptTest extends TestBase {
 
-    @org.junit.Ignore @Test public void testInfiniteLoopInScript() {
+    @Test public void testInfiniteLoopInScript() {
         try {
             // This infinite loop should get interrupted by Webkit in about 10s.
             // If it doesn't, test times out.
@@ -26,24 +25,43 @@
             }
         }
     }
-    
-    @Test public void testInfiniteLoopInHandler() {
+
+    @Test public void testLongWaitInHandler() {
         // This test verifies that user code is not subject to Webkit timeout.
         // It installs an alert handler that takes TIMEOUT seconds to run,
         // and checks that it is not interrupted.
         final int TIMEOUT = 24;    // seconds
-        final AtomicBoolean passed = new AtomicBoolean(false);
         getEngine().setOnAlert(new EventHandler<WebEvent<String>>() {
             public void handle(WebEvent<String> ev) {
                 try {
                     synchronized (this) {
                         wait(TIMEOUT * 1000);
                     }
-                    passed.set(true);
                 } catch (InterruptedException e) {
                 }
             }
         });
         executeScript("alert('Jumbo!');");
     }
+
+    @Test public void testLongLoopInHandler() {
+        // This test verifies that user code is not subject to Webkit timeout.
+        // The test installs an alert handler that takes a sufficiently large
+        // amount of CPU time to run, and checks that the handler is not
+        // interrupted.
+        final long CPU_TIME_TO_RUN = 24L * 1000 * 1000 * 1000;
+        getEngine().setOnAlert(new EventHandler<WebEvent<String>>() {
+            public void handle(WebEvent<String> ev) {
+                ThreadMXBean bean = ManagementFactory.getThreadMXBean();
+                long startCpuTime = bean.getCurrentThreadCpuTime();
+                while (bean.getCurrentThreadCpuTime() - startCpuTime
+                        < CPU_TIME_TO_RUN)
+                {
+                    // Do something that consumes CPU time
+                    Math.sqrt(Math.random() * 21082013);
+                }
+            }
+        });
+        executeScript("alert('Jumbo!');");
+    }
 }
--- a/netbeans/graphics/build.xml	Tue Sep 03 12:13:17 2013 -0400
+++ b/netbeans/graphics/build.xml	Tue Sep 03 09:40:03 2013 -0700
@@ -102,5 +102,27 @@
             </sequential>
         </macrodef>
     </target>
-
+    <target depends="-init-macrodef-junit-debug-impl" if="${junit.available}" name="-init-macrodef-test-debug-junit">
+        <macrodef name="test-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <attribute default="${main.class}" name="testClass"/>
+            <attribute default="" name="testMethod"/>
+            <sequential>
+                <j2seproject3:test-debug-impl excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
+                    <customize>
+                        <classpath>
+                            <path path="${run.test.classpath}"/>
+                        </classpath>
+                        <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+                        <jvmarg line="${run.jvmargs}"/>
+                        <jvmarg line="${run.jvmargs.ide}"/>
+                        <jvmarg line="-Djavafx.toolkit=com.sun.javafx.pgstub.StubToolkit"/>
+                    </customize>
+                </j2seproject3:test-debug-impl>
+            </sequential>
+        </macrodef>
+    </target>
 </project>
--- a/tools/gltrace/Makefile	Tue Sep 03 12:13:17 2013 -0400
+++ b/tools/gltrace/Makefile	Tue Sep 03 09:40:03 2013 -0700
@@ -1,75 +1,10 @@
-CC      = gcc -O2 
-JDK     = /opt/java
 
-PLATFORM := $(shell if [ -x /opt/vc ]; then echo RASPBERRY; else echo BEAGLE; fi)
+UNAME_S         := $(shell uname -s)
 
-ifeq ($(PLATFORM),RASPBERRY)
-CFLAGS += -DRASPBERRYPI=1 -I/opt/vc/include -I/opt/vc/include/interface/vcos/pthreads -L/opt/vc/lib
-DEST = armv6hf-vfp
+ifeq ($(UNAME_S),Darwin)
+include Makefile.macosx
 endif
 
-ifeq ($(PLATFORM),BEAGLE)
-CFLAGS += -DBEAGLEBOARD
-DEST = armv6-vfp
+ifeq ($(UNAME_S),Linux)
+include Makefile.linux
 endif
-
-TARGETS = $(DEST)/gltrace.so $(DEST)/gltrace
-
-default: all
-
-all: $(DEST) $(TARGETS)
-
-$(DEST):
-	if [ ! -x $(DEST) ]; then mkdir -m 755 -p $(DEST); fi
-
-#
-#    gltrace.so
-#
-
-HDRS    = iolib.h map.h os.h trace.h
-DYNLIB_SRCS = trace-linux.c agent.c iolib.c os-linux.c egl.c gles.c
-
-$(DEST)/gltrace.so: $(HDRS) $(DYNLIB_SRCS)
-	$(CC) $(CFLAGS) -shared -fPIC \
-	-I$(JDK)/include -I$(JDK)/include/linux \
-	-ldl -lEGL -lGLESv2 \
-	-o $@ $(DYNLIB_SRCS) 
-
-#
-#    gltrace
-#
-
-GLTRACE_SRCS = retrace.c iolib.c enums.c map.c os-linux.c
-
-$(DEST)/gltrace: $(HDRS) $(GLTRACE_SRCS)
-	$(CC) $(CFLAGS) -o $@ $(GLTRACE_SRCS) -lEGL -lGLESv2 -lrt -lpng
-
-#
-#    examples
-#
-
-JAVA    = $(JDK)/bin/java
-JVMOPTS =
-JAVAFX  = /opt/javafx/lib/ext/jfxrt.jar
-JFXOPTS =
-
-RUNJFX  = $(JAVA) $(JVMOPTS) $(JFXOPTS)
-
-TEST    =
-ARGS    =
-
-trace:
-	export LD_PRELOAD=$(DEST)/gltrace.so; \
-	$(RUNJFX) -cp "$(JAVAFX):$(JAR)" $(TEST) $(ARGS)
-
-replay:
-	$(DEST)/gltrace -replay
-
-dump:
-	$(DEST)/gltrace -print
-
-interactive:
-	$(DEST)/gltrace
-
-clean:
-	rm -rf $(TARGETS)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/gltrace/Makefile.linux	Tue Sep 03 09:40:03 2013 -0700
@@ -0,0 +1,75 @@
+CC      = gcc -O2 
+JDK     = /opt/java
+
+PLATFORM := $(shell if [ -x /opt/vc ]; then echo RASPBERRY; else echo BEAGLE; fi)
+
+ifeq ($(PLATFORM),RASPBERRY)
+CFLAGS += -DRASPBERRYPI=1 -I/opt/vc/include -I/opt/vc/include/interface/vcos/pthreads -L/opt/vc/lib
+DEST = armv6hf-vfp
+endif
+
+ifeq ($(PLATFORM),BEAGLE)
+CFLAGS += -DBEAGLEBOARD
+DEST = armv6-vfp
+endif
+
+TARGETS = $(DEST)/gltrace.so $(DEST)/gltrace
+
+default: all
+
+all: $(DEST) $(TARGETS)
+
+$(DEST):
+	if [ ! -x $(DEST) ]; then mkdir -m 755 -p $(DEST); fi
+
+#
+#    gltrace.so
+#
+
+HDRS    = trace.h iolib.h map.h os.h
+DYNLIB_SRCS = trace-linux.c agent.c iolib.c os-linux.c egl.c gles.c
+
+$(DEST)/gltrace.so: $(HDRS) $(DYNLIB_SRCS)
+	$(CC) $(CFLAGS) -shared -fPIC \
+	-I$(JDK)/include -I$(JDK)/include/linux \
+	-ldl -lEGL -lGLESv2 \
+	-o $@ $(DYNLIB_SRCS) 
+
+#
+#    gltrace
+#
+
+GLTRACE_SRCS = retrace.c iolib.c enums.c map.c os-linux.c
+
+$(DEST)/gltrace: $(HDRS) $(GLTRACE_SRCS)
+	$(CC) $(CFLAGS) -o $@ $(GLTRACE_SRCS) -lEGL -lGLESv2 -lrt -lpng
+
+#
+#    examples
+#
+
+JAVA    = $(JDK)/bin/java
+JVMOPTS =
+JAVAFX  = /opt/javafx/lib/ext/jfxrt.jar
+JFXOPTS =
+
+RUNJFX  = $(JAVA) $(JVMOPTS) $(JFXOPTS)
+
+TEST    =
+ARGS    =
+
+trace:
+	export LD_PRELOAD=$(DEST)/gltrace.so; \
+	$(RUNJFX) -cp "$(JAVAFX):$(JAR)" $(TEST) $(ARGS)
+
+replay:
+	$(DEST)/gltrace -replay
+
+dump:
+	$(DEST)/gltrace -print
+
+interactive:
+	$(DEST)/gltrace
+
+clean:
+	rm -rf $(TARGETS)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/gltrace/Makefile.macosx	Tue Sep 03 09:40:03 2013 -0700
@@ -0,0 +1,36 @@
+CC	 = gcc
+JDK     = /System/Library/Frameworks/JavaVM.framework/Versions/Current
+DEST	= macosx-universal
+CFLAGS	= -O2 -DMACOSX=1
+TARGETS = $(DEST)/gltrace.dylib $(DEST)/gltrace
+
+default: all
+
+all: $(DEST) $(TARGETS)
+
+$(DEST):
+	if [ ! -x $(DEST) ]; then mkdir -m 755 -p $(DEST); fi
+
+#
+#    gltrace.dylib
+#
+
+HDRS    = trace.h iolib.h map.h os.h
+DYNLIB_SRCS = trace-macosx.c agent.c iolib.c os-macosx.c gles.c
+
+$(DEST)/gltrace.dylib: $(HDRS) $(DYNLIB_SRCS)
+	$(CC) $(CFLAGS) -I$(JDK)/Headers \
+	-dynamiclib -framework OpenGL -ldl -lpthread -lobjc \
+	-o $@ $(DYNLIB_SRCS) 
+
+#
+#    gltrace
+#
+
+GLTRACE_SRCS = retrace.c iolib.c enums.c map.c os-macosx.c
+
+$(DEST)/gltrace: $(HDRS) $(GLTRACE_SRCS)
+	$(CC) $(CFLAGS) -o $@ $(GLTRACE_SRCS) -framework OpenGL -framework libpng
+
+
+
--- a/tools/gltrace/egl.c	Tue Sep 03 12:13:17 2013 -0400
+++ b/tools/gltrace/egl.c	Tue Sep 03 09:40:03 2013 -0700
@@ -24,21 +24,16 @@
  */
  
 #define _GNU_SOURCE
-#include <alloca.h>
 #include <dlfcn.h>
 #include <errno.h>
-#include <link.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
-#include <EGL/egl.h>
-
 #include "os.h"
 #include "iolib.h"
-#include "trace.h"
+#include "egl.h"
 
-static int tLevel = trcLevel;
 static void *libEGL = NULL;
 
 /*
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/gltrace/egl.h	Tue Sep 03 09:40:03 2013 -0700
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+ 
+#ifndef GLTRACE_EGL_H
+#define GLTRACE_EGL_H
+
+#include <EGL/egl.h>
+#include "trace.h"
+
+#define EGLPROLOG(func) \
+    static void *orig = NULL;\
+    if (orig == NULL) {\
+        DLFCN_HOOK_POP(); \
+        orig = dlsym(libEGL, #func);\
+        DLFCN_HOOK_PUSH(); \
+    }
+
+#define EGLEPILOG() 
+
+#endif /* GLTRACE_EGL_H */
--- a/tools/gltrace/enums.c	Tue Sep 03 12:13:17 2013 -0400
+++ b/tools/gltrace/enums.c	Tue Sep 03 09:40:03 2013 -0700
@@ -26,10 +26,36 @@
 #include <stdio.h>
 #include <string.h>
 
+#if linux
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
 #include <EGL/egl.h>
+#endif
 
+#if MACOSX
+#include <OpenGL/gl.h>
+#include <OpenGL/glext.h>
+
+#define GL_FIXED                            0x10000
+#define GL_MAX_VERTEX_UNIFORM_VECTORS       0x10001
+#define GL_MAX_VARYING_VECTORS              0x10002
+#define GL_MAX_FRAGMENT_UNIFORM_VECTORS     0x10003
+#define GL_IMPLEMENTATION_COLOR_READ_TYPE   0x10004
+#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x10005
+#define GL_SHADER_COMPILER                  0x10006
+#define GL_SHADER_BINARY_FORMATS            0x10007
+#define GL_NUM_SHADER_BINARY_FORMATS        0x10008
+#define GL_LOW_FLOAT                        0x10009
+#define GL_MEDIUM_FLOAT                     0x10010
+#define GL_HIGH_FLOAT                       0x10011
+#define GL_LOW_INT                          0x10012
+#define GL_MEDIUM_INT                       0x10013
+#define GL_HIGH_INT                         0x10014
+#define GL_RGB565                           0x10015
+#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x10016
+#endif
+
+#if linux
 const char *
 eglEnum2str(EGLenum val)
 {
@@ -141,6 +167,7 @@
     ptr += strlen(ptr) + 1;
     return res;
 }
+#endif /* linux */
 
 const char *
 glEnum2str(GLenum val)
--- a/tools/gltrace/gles.c	Tue Sep 03 12:13:17 2013 -0400
+++ b/tools/gltrace/gles.c	Tue Sep 03 09:40:03 2013 -0700
@@ -24,21 +24,16 @@
  */
  
 #define _GNU_SOURCE
-#include <alloca.h>
 #include <dlfcn.h>
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-
 #include "os.h"
 #include "iolib.h"
-#include "trace.h"
+#include "gles.h"
 
-static int tLevel = trcLevel;
 static void *libGLESv2 = NULL;
 
 /*
@@ -105,28 +100,70 @@
 glElementSize(GLenum format, GLenum type)
 {
     switch (type) {
-    case GL_UNSIGNED_BYTE:
-        switch (format) {
-        case GL_ALPHA:          return 1;
-        case GL_RGB:            return 3;
-        case GL_RGBA:
-        case GL_BGRA:           return 4;
-        case GL_LUMINANCE:      return 1;       /* XXX validate */
-        case GL_LUMINANCE_ALPHA: return 2;      /* XXX validate */
-        }
-        fprintf(stderr, "FATAL: glElementSize: unknown format: 0x%x\n", format);
-        exit(1);
-        return 0;
-    case GL_UNSIGNED_SHORT_4_4_4_4:
-    case GL_UNSIGNED_SHORT_5_5_5_1:
-    case GL_UNSIGNED_SHORT_5_6_5:
-        return 2; /* XXX validate */
+        case GL_UNSIGNED_BYTE:
+            switch (format) {
+                case GL_ALPHA:          return 1;
+                case GL_RGB:            return 3;
+                case GL_RGBA:
+                case GL_BGRA:           return 4;
+                case GL_LUMINANCE:      return 1;
+                case GL_LUMINANCE_ALPHA: return 2;
+            }
+            fprintf(stderr, "FATAL: glElementSize: unknown format: 0x%x\n", format);
+            exit(1);
+            return 0;
+        case GL_UNSIGNED_SHORT_4_4_4_4:
+        case GL_UNSIGNED_SHORT_5_5_5_1:
+        case GL_UNSIGNED_SHORT_5_6_5:
+            return 2;
+#if MACOSX
+        case GL_UNSIGNED_INT_8_8_8_8_REV:
+            return 4;
+#endif
     }
     fprintf(stderr, "FATAL: glElementSize: unknown type: 0x%x\n", type);
     exit(1);
     return 0;
 }
 
+static GLuint arrayBufferBinding = 0;
+static GLuint elementArrayBufferBinding = 0;
+static GLuint elementArrayBufferData = 0;
+static GLvoid *elementArrayData = NULL;
+
+static GLsizei
+getVertexCount(GLsizei count, GLenum type, const GLvoid* indices)
+{
+#if MT_BUFFER_DATA_FIXED
+    uint8_t *ptr = (uint8_t*)indices;
+    if (elementArrayBufferBinding) {
+        if (elementArrayBufferData != elementArrayBufferBinding) {
+            fprintf(out, "FATAL: multiple element arrays not implemented\n");
+            exit(1);
+        }
+        ptr = (uint8_t*)elementArrayData + (long)indices;
+    }
+    
+    GLsizei i, maxval = 0;
+    for (i=0; i<count; ++i) {
+        int val;
+        switch (type) {
+            case GL_UNSIGNED_BYTE: val = ptr[i]; break;
+            case GL_UNSIGNED_SHORT: val = ((uint16_t*)ptr)[i]; break;
+            case GL_UNSIGNED_INT: val = ((uint32_t*)ptr)[i]; break;
+            default:
+                fprintf(out, "FATAL: glDrawElements: type %d not implemented\n", type);
+                exit(1);
+                break;
+        }
+        if (maxval < val) maxval = val;
+    }
+    return maxval + 1;  // count = max index + 1
+#else
+    return count/6*4; /* XXX hack for quads only */ 
+#endif
+}
+
 /* XXX use glGet(GL_MAX_VERTEX_ATTRIBS) */
 #define MAX_VERTEX_ATTRIBS      128     
 typedef struct VertexAttrib_t {
@@ -141,17 +178,24 @@
 static VertexAttrib_t vertexAttrib[MAX_VERTEX_ATTRIBS];
 
 static void
-putVertexAttrib(int count)
+putVertexAttrib(GLsizei count, GLenum type, const GLvoid* indices)
 {
-    count = count/6 * 4; /* XXX hack for quads only */
-    char *buf = alloca(count * 4 * sizeof(float));
+    count = getVertexCount(count, type, indices);
+    int maxsz = 0;
+    int i;
+    for (i=0; i<MAX_VERTEX_ATTRIBS; ++i) {
+        if (!vertexAttrib[i].enabled) continue;
+        int sz = glSizeof(vertexAttrib[i].type) * vertexAttrib[i].size *count;
+        if (maxsz < sz) maxsz = sz;
+    }
+    char *buf = alloca(maxsz);
     
-    int i, j, k;
     for (i=0; i<MAX_VERTEX_ATTRIBS; ++i) {
         if (!vertexAttrib[i].enabled) continue;
         char *src = (char*)vertexAttrib[i].pointer;
         char *dst = buf;
         int elemsz = glSizeof(vertexAttrib[i].type) * vertexAttrib[i].size;
+        int j, k;
         for (j=0; j<count; ++j) {
             for (k=0; k<elemsz; ++k) *dst++ = *src++;
             if (vertexAttrib[i].stride > 0) {
@@ -162,45 +206,43 @@
     }
 }
 
-static GLuint arrayBufferBinding = 0;
-static GLuint elementArrayBufferBinding = 0;
 
 DEF(void, glActiveTexture)(GLenum texture)
 {
-    GLPROLOG(glActiveTexture);
+    GLESPROLOG(glActiveTexture);
     
     putCmd(OPC_glActiveTexture);
     putInt(texture);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(texture);
+    ORIG(glActiveTexture)(texture);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
-DEF(void, glAttachShader) (GLuint program, GLuint shader)
+DEF(void, glAttachShader)(GLuint program, GLuint shader)
 {
-    GLPROLOG(glAttachShader);
+    GLESPROLOG(glAttachShader);
     
     putCmd(OPC_glAttachShader);
     putInt(program);
     putInt(shader);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(program, shader);
+    ORIG(glAttachShader)(program, shader);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glBindAttribLocation) (GLuint program, GLuint index, const GLchar* name)
 {
-    GLPROLOG(glBindAttribLocation);
+    GLESPROLOG(glBindAttribLocation);
     
     putCmd(OPC_glBindAttribLocation);
     putInt(program);
@@ -208,24 +250,24 @@
     putString(name);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(program, index, name);
+    ORIG(glBindAttribLocation)(program, index, name);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glBindBuffer) (GLenum target, GLuint buffer)
 {
-    GLPROLOG(glBindBuffer);
+    GLESPROLOG(glBindBuffer);
     
     putCmd(OPC_glBindBuffer);
     putInt(target);
     putInt(buffer);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(target, buffer);
+    ORIG(glBindBuffer)(target, buffer);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
@@ -237,63 +279,63 @@
         elementArrayBufferBinding = buffer;
     }
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glBindFramebuffer) (GLenum target, GLuint framebuffer)
 {
-    GLPROLOG(glBindFramebuffer);
+    GLESPROLOG(glBindFramebuffer);
     
     putCmd(OPC_glBindFramebuffer);
     putInt(target);
     putInt(framebuffer);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(target, framebuffer);
+    ORIG(glBindFramebuffer)(target, framebuffer);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glBindRenderbuffer) (GLenum target, GLuint renderbuffer)
 {
-    GLPROLOG(glBindRenderbuffer);
+    GLESPROLOG(glBindRenderbuffer);
     
     putCmd(OPC_glBindRenderbuffer);
     putInt(target);
     putInt(renderbuffer);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(target, renderbuffer);
+    ORIG(glBindRenderbuffer)(target, renderbuffer);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glBindTexture) (GLenum target, GLuint texture)
 {
-    GLPROLOG(glBindTexture);
+    GLESPROLOG(glBindTexture);
     
     putCmd(OPC_glBindTexture);
     putInt(target);
     putInt(texture);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(target, texture);
+    ORIG(glBindTexture)(target, texture);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glBlendColor) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
 {
-    GLPROLOG(glBlendColor);
+    GLESPROLOG(glBlendColor);
 
     putCmd(OPC_glBlendColor);
     putFloat(red);
@@ -302,67 +344,67 @@
     putFloat(alpha);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)(GLclampf, GLclampf, GLclampf, GLclampf))orig)(red, green, blue, alpha);
+    ORIG(glBlendColor)(red, green, blue, alpha);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
     
-    GLEPILOG();
+    GLESEPILOG();
 }
 
 DEF(void, glBlendEquation) (GLenum mode)
 {
-    GLPROLOG(glBlendEquation);
+    GLESPROLOG(glBlendEquation);
     
     putCmd(OPC_glBlendEquation);
     putInt(mode);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(mode);
+    ORIG(glBlendEquation)(mode);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
     
-    GLEPILOG();
+    GLESEPILOG();
 }
 
 DEF(void, glBlendEquationSeparate) (GLenum modeRGB, GLenum modeAlpha)
 {
-    GLPROLOG(glBlendEquationSeparate);
+    GLESPROLOG(glBlendEquationSeparate);
 
     putCmd(OPC_glBlendEquationSeparate);
     putInt(modeRGB);
     putInt(modeAlpha);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(modeRGB, modeAlpha);
+    ORIG(glBlendEquationSeparate)(modeRGB, modeAlpha);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
     
-    GLEPILOG();
+    GLESEPILOG();
 }
 
 DEF(void, glBlendFunc) (GLenum sfactor, GLenum dfactor)
 {
-    GLPROLOG(glBlendFunc);
+    GLESPROLOG(glBlendFunc);
     
     putCmd(OPC_glBlendFunc);
     putInt(sfactor);
     putInt(dfactor);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(sfactor, dfactor);
+    ORIG(glBlendFunc)(sfactor, dfactor);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glBlendFuncSeparate) (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
 {
-    GLPROLOG(glBlendFuncSeparate);
+    GLESPROLOG(glBlendFuncSeparate);
     
     putCmd(OPC_glBlendFuncSeparate);
     putInt(srcRGB);
@@ -371,17 +413,17 @@
     putInt(dstAlpha);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(srcRGB, dstRGB, srcAlpha, dstAlpha);
+    ORIG(glBlendFuncSeparate)(srcRGB, dstRGB, srcAlpha, dstAlpha);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
     
-    GLEPILOG();
+    GLESEPILOG();
 }
 
 DEF(void, glBufferData) (GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage)
 {
-    GLPROLOG(glBufferData);
+    GLESPROLOG(glBufferData);
     
     putCmd(OPC_glBufferData);
     putInt(target);
@@ -390,17 +432,17 @@
     putInt(usage);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(target, size, data, usage);
+    ORIG(glBufferData)(target, size, data, usage);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glBufferSubData) (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data)
 {
-    GLPROLOG(glBufferSubData);
+    GLESPROLOG(glBufferSubData);
 
     putCmd(OPC_glBufferSubData);
     putInt(target);
@@ -409,52 +451,52 @@
     putBytes(data, size);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(target, offset, size, data);
+    ORIG(glBufferSubData)(target, offset, size, data);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
     
-    GLEPILOG();
+    GLESEPILOG();
 }
 
 DEF(GLenum, glCheckFramebufferStatus) (GLenum target)
 {
-    GLPROLOG(glCheckFramebufferStatus);
+    GLESPROLOG(glCheckFramebufferStatus);
     
     putCmd(OPC_glCheckFramebufferStatus);
     putInt(target);
     
     uint64_t bgn = gethrtime();
-    GLenum res = (*(GLenum(*)())orig)(target);
+    GLenum res = ORIG(glCheckFramebufferStatus)(target);
     uint64_t end = gethrtime();
     
     putInt(res);
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
     
     return res;
 }    
 
 DEF(void, glClear) (GLbitfield mask)
 {
-    GLPROLOG(glClear);
+    GLESPROLOG(glClear);
     
     putCmd(OPC_glClear);
     putInt(mask);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(mask);
+    ORIG(glClear)(mask);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glClearColor) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
 {
-    GLPROLOG(glClearColor);
+    GLESPROLOG(glClearColor);
     
     putCmd(OPC_glClearColor);
     putFloat(red);
@@ -463,50 +505,51 @@
     putFloat(alpha);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)(GLclampf, GLclampf, GLclampf, GLclampf))orig)(red, green, blue, alpha);
+    ORIG(glClearColor)(red, green, blue, alpha);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
-GL_APICALL void GL_APIENTRY 
-glClearDepthf (GLclampf depth)
+#if !MACOSX
+DEF(void, glClearDepthf) (GLclampf depth)
 {
-    GLPROLOG(glClearDepthf);
+    GLESPROLOG(glClearDepthf);
     
     putCmd(OPC_glClearDepthf);
     putFloat(depth);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)(GLclampf))orig)(depth);
+    ORIG(glClearDepthf)(depth);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
-}    
+    GLESEPILOG();
+}
+#endif
 
 DEF(void, glClearStencil) (GLint s)
 {
-    GLPROLOG(glClearStencil);
+    GLESPROLOG(glClearStencil);
     
     putCmd(OPC_glClearStencil);
     putInt(s);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(s);
+    ORIG(glClearStencil)(s);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
     
-    GLEPILOG();
+    GLESEPILOG();
 }
 
 DEF(void, glColorMask) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
 {
-    GLPROLOG(glColorMask);
+    GLESPROLOG(glColorMask);
     
     putCmd(OPC_glColorMask);
     putInt(red);
@@ -515,33 +558,33 @@
     putInt(alpha);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(red, green, blue, alpha);
+    ORIG(glColorMask)(red, green, blue, alpha);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
     
-    GLEPILOG();
+    GLESEPILOG();
 }
 
 DEF(void, glCompileShader) (GLuint shader)
 {
-    GLPROLOG(glCompileShader);
+    GLESPROLOG(glCompileShader);
     
     putCmd(OPC_glCompileShader);
     putInt(shader);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(shader);
+    ORIG(glCompileShader)(shader);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glCompressedTexImage2D) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data)
 {
-    GLPROLOG(glCompressedTexImage2D);
+    GLESPROLOG(glCompressedTexImage2D);
 
     putCmd(OPC_glCompressedTexImage2D);
     putInt(target);
@@ -554,17 +597,17 @@
     putBytes(data, imageSize);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(target, level, internalformat, width, height, border, imageSize, data);
+    ORIG(glCompressedTexImage2D)(target, level, internalformat, width, height, border, imageSize, data);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
     
-    GLEPILOG();
+    GLESEPILOG();
 }
 
 DEF(void, glCompressedTexSubImage2D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data)
 {
-    GLPROLOG(glCompressedTexSubImage2D);
+    GLESPROLOG(glCompressedTexSubImage2D);
 
     putCmd(OPC_glCompressedTexSubImage2D);
     putInt(target);
@@ -578,17 +621,17 @@
     putBytes(data, imageSize);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(target, level, xoffset, yoffset, width, height, format, imageSize, data);
+    ORIG(glCompressedTexSubImage2D)(target, level, xoffset, yoffset, width, height, format, imageSize, data);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
     
-    GLEPILOG();
+    GLESEPILOG();
 }
 
 DEF(void, glCopyTexImage2D) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
 {
-    GLPROLOG(glCopyTexImage2D);
+    GLESPROLOG(glCopyTexImage2D);
     
     putCmd(OPC_glCopyTexImage2D);
     putInt(target);
@@ -601,17 +644,17 @@
     putInt(border);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(target, level, internalformat, x, y, width, height, border);
+    ORIG(glCopyTexImage2D)(target, level, internalformat, x, y, width, height, border);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
     
-    GLEPILOG();
+    GLESEPILOG();
 }
 
 DEF(void, glCopyTexSubImage2D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
 {
-    GLPROLOG(glCopyTexSubImage2D);
+    GLESPROLOG(glCopyTexSubImage2D);
     
     putCmd(OPC_glCopyTexSubImage2D);
     putInt(target);
@@ -624,70 +667,70 @@
     putInt(height);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(target, level, xoffset, yoffset, x, y, width, height);
+    ORIG(glCopyTexSubImage2D)(target, level, xoffset, yoffset, x, y, width, height);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
     
-    GLEPILOG();
+    GLESEPILOG();
 }
 
 DEF(GLuint, glCreateProgram) (void)
 {
-    GLPROLOG(glCreateProgram);
+    GLESPROLOG(glCreateProgram);
     
     putCmd(OPC_glCreateProgram);
     
     uint64_t bgn = gethrtime();
-    GLuint res = (*(GLuint(*)())orig)();
+    GLuint res = ORIG(glCreateProgram)();
     uint64_t end = gethrtime();
     
     putInt(res);
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
     
     return res;
 }    
 
 DEF(GLuint, glCreateShader) (GLenum type)
 {
-    GLPROLOG(glCreateShader);
+    GLESPROLOG(glCreateShader);
     
     putCmd(OPC_glCreateShader);
     putInt(type);
     
     uint64_t bgn = gethrtime();
-    GLuint res = (*(GLuint(*)())orig)(type);
+    GLuint res = ORIG(glCreateShader)(type);
     uint64_t end = gethrtime();
     
     putInt(res);
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
     
     return res;
 }    
 
 DEF(void, glCullFace) (GLenum mode)
 {
-    GLPROLOG(glCullFace);
+    GLESPROLOG(glCullFace);
     
     putCmd(OPC_glCullFace);
     putInt(mode);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(mode);
+    ORIG(glCullFace)(mode);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glDeleteBuffers) (GLsizei n, const GLuint* buffers)
 {
-    GLPROLOG(glDeleteBuffers);
+    GLESPROLOG(glDeleteBuffers);
     
     putCmd(OPC_glDeleteBuffers);
     putInt(n);
@@ -697,17 +740,17 @@
     }
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(n, buffers);
+    ORIG(glDeleteBuffers)(n, buffers);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glDeleteFramebuffers) (GLsizei n, const GLuint* framebuffers)
 {
-    GLPROLOG(glDeleteFramebuffers);
+    GLESPROLOG(glDeleteFramebuffers);
     
     putCmd(OPC_glDeleteFramebuffers);
     putInt(n);
@@ -717,33 +760,33 @@
     }
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(n, framebuffers);
+    ORIG(glDeleteFramebuffers)(n, framebuffers);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glDeleteProgram) (GLuint program)
 {
-    GLPROLOG(glDeleteProgram);
+    GLESPROLOG(glDeleteProgram);
     
     putCmd(OPC_glDeleteProgram);
     putInt(program);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(program);
+    ORIG(glDeleteProgram)(program);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
     
-    GLEPILOG();
+    GLESEPILOG();
 }
 
 DEF(void, glDeleteRenderbuffers) (GLsizei n, const GLuint* renderbuffers)
 {
-    GLPROLOG(glDeleteRenderbuffers);
+    GLESPROLOG(glDeleteRenderbuffers);
     
     putCmd(OPC_glDeleteRenderbuffers);
     putInt(n);
@@ -753,33 +796,33 @@
     }
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(n, renderbuffers);
+    ORIG(glDeleteRenderbuffers)(n, renderbuffers);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
     
-    GLEPILOG();
+    GLESEPILOG();
 }
 
 DEF(void, glDeleteShader) (GLuint shader)
 {
-    GLPROLOG(glDeleteShader);
+    GLESPROLOG(glDeleteShader);
     
     putCmd(OPC_glDeleteShader);
     putInt(shader);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(shader);
+    ORIG(glDeleteShader)(shader);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
     
-    GLEPILOG();
+    GLESEPILOG();
 }
 
 DEF(void, glDeleteTextures) (GLsizei n, const GLuint* textures)
 {
-    GLPROLOG(glDeleteTextures);
+    GLESPROLOG(glDeleteTextures);
     
     putCmd(OPC_glDeleteTextures);
     putInt(n);
@@ -789,116 +832,118 @@
     }
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(n, textures);
+    ORIG(glDeleteTextures)(n, textures);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glDepthFunc) (GLenum func)
 {
-    GLPROLOG(glDepthFunc);
+    GLESPROLOG(glDepthFunc);
     
     putCmd(OPC_glDepthFunc);
     putInt(func);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(func);
+    ORIG(glDepthFunc)(func);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glDepthMask) (GLboolean flag)
 {
-    GLPROLOG(glDepthMask);
+    GLESPROLOG(glDepthMask);
     
     putCmd(OPC_glDepthMask);
     putInt(flag);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(flag);
+    ORIG(glDepthMask)(flag);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
+#if !MACOSX
 DEF(void, glDepthRangef) (GLclampf zNear, GLclampf zFar)
 {
-    GLPROLOG(glDepthRangef);
+    GLESPROLOG(glDepthRangef);
     
     putCmd(OPC_glDepthRangef);
     putFloat(zNear);
     putFloat(zFar);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)(GLclampf, GLclampf))orig)(zNear, zFar);
+    ORIG(glDepthRangef)(zNear, zFar);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
     
-    GLEPILOG();
+    GLESEPILOG();
 }
+#endif
 
 DEF(void, glDetachShader) (GLuint program, GLuint shader)
 {
-    GLPROLOG(glDetachShader);
+    GLESPROLOG(glDetachShader);
     
     putCmd(OPC_glDetachShader);
     putInt(program);
     putInt(shader);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(program, shader);
+    ORIG(glDetachShader)(program, shader);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
     
-    GLEPILOG();
+    GLESEPILOG();
 }
 
 DEF(void, glDisable) (GLenum cap)
 {
-    GLPROLOG(glDisable);
+    GLESPROLOG(glDisable);
     
     putCmd(OPC_glDisable);
     putInt(cap);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(cap);
+    ORIG(glDisable)(cap);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glDisableVertexAttribArray) (GLuint index)
 {
-    GLPROLOG(glDisableVertexAttribArray);
+    GLESPROLOG(glDisableVertexAttribArray);
     
     putCmd(OPC_glDisableVertexAttribArray);
     putInt(index);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(index);
+    ORIG(glDisableVertexAttribArray)(index);
     uint64_t end = gethrtime();
     
     vertexAttrib[index].enabled = 0;
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glDrawArrays) (GLenum mode, GLint first, GLsizei count)
 {
-    GLPROLOG(glDrawArrays);
+    GLESPROLOG(glDrawArrays);
     
     putCmd(OPC_glDrawArrays);
     putInt(mode);
@@ -906,102 +951,107 @@
     putInt(count);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(mode, first, count);
+    ORIG(glDrawArrays)(mode, first, count);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glDrawElements) (GLenum mode, GLsizei count, GLenum type, const GLvoid* indices)
 {
-    GLPROLOG(glDrawElements);
+    GLESPROLOG(glDrawElements);
     
     putCmd(OPC_glDrawElements);
     putInt(mode);
     putInt(count);
     putInt(type);
-    putBytes(indices, count * glSizeof(type));
+    if (elementArrayBufferBinding) {
+        putPtr(indices);
+    }
+    else {
+        putBytes(indices, count * glSizeof(type));
+    }    
     if (!arrayBufferBinding) {
-        putVertexAttrib(count);
+        putVertexAttrib(count, type, indices);
     }
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(mode, count, type, indices);
+    ORIG(glDrawElements)(mode, count, type, indices);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glEnable) (GLenum cap)
 {
-    GLPROLOG(glEnable);
+    GLESPROLOG(glEnable);
     
     putCmd(OPC_glEnable);
     putInt(cap);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(cap);
+    ORIG(glEnable)(cap);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glEnableVertexAttribArray) (GLuint index)
 {
-    GLPROLOG(glEnableVertexAttribArray);
+    GLESPROLOG(glEnableVertexAttribArray);
     
     putCmd(OPC_glEnableVertexAttribArray);
     putInt(index);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(index);
+    ORIG(glEnableVertexAttribArray)(index);
     uint64_t end = gethrtime();
     
     vertexAttrib[index].enabled = 1;
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glFinish) (void)
 {
-    GLPROLOG(glFinish);
+    GLESPROLOG(glFinish);
     
     putCmd(OPC_glFinish);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)();
+    ORIG(glFinish)();
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glFlush) (void)
 {
-    GLPROLOG(glFlush);
+    GLESPROLOG(glFlush);
     
     putCmd(OPC_glFlush);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)();
+    ORIG(glFlush)();
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glFramebufferRenderbuffer) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
 {
-    GLPROLOG(glFramebufferRenderbuffer);
+    GLESPROLOG(glFramebufferRenderbuffer);
     
     putCmd(OPC_glFramebufferRenderbuffer);
     putInt(target);
@@ -1010,17 +1060,17 @@
     putInt(renderbuffer);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(target, attachment, renderbuffertarget, renderbuffer);
+    ORIG(glFramebufferRenderbuffer)(target, attachment, renderbuffertarget, renderbuffer);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glFramebufferTexture2D) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
 {
-    GLPROLOG(glFramebufferTexture2D);
+    GLESPROLOG(glFramebufferTexture2D);
     
     putCmd(OPC_glFramebufferTexture2D);
     putInt(target);
@@ -1030,39 +1080,39 @@
     putInt(level);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(target, attachment, textarget, texture, level);
+    ORIG(glFramebufferTexture2D)(target, attachment, textarget, texture, level);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glFrontFace) (GLenum mode)
 {
-    GLPROLOG(glFrontFace);
+    GLESPROLOG(glFrontFace);
     
     putCmd(OPC_glFrontFace);
     putInt(mode);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(mode);
+    ORIG(glFrontFace)(mode);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glGenBuffers) (GLsizei n, GLuint* buffers)
 {
-    GLPROLOG(glGenBuffers);
+    GLESPROLOG(glGenBuffers);
     
     putCmd(OPC_glGenBuffers);
     putInt(n);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(n, buffers);
+    ORIG(glGenBuffers)(n, buffers);
     uint64_t end = gethrtime();
     
     int i;
@@ -1071,34 +1121,34 @@
     }
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glGenerateMipmap) (GLenum target)
 {
-    GLPROLOG(glGenerateMipmap);
+    GLESPROLOG(glGenerateMipmap);
     
     putCmd(OPC_glGenerateMipmap);
     putInt(target);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(target);
+    ORIG(glGenerateMipmap)(target);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
     
-    GLEPILOG();
+    GLESEPILOG();
 }
 
 DEF(void, glGenFramebuffers) (GLsizei n, GLuint* framebuffers)
 {
-    GLPROLOG(glGenFramebuffers);
+    GLESPROLOG(glGenFramebuffers);
     
     putCmd(OPC_glGenFramebuffers);
     putInt(n);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(n, framebuffers);
+    ORIG(glGenFramebuffers)(n, framebuffers);
     uint64_t end = gethrtime();
     
     int i;
@@ -1107,18 +1157,18 @@
     }
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glGenRenderbuffers) (GLsizei n, GLuint* renderbuffers)
 {
-    GLPROLOG(glGenRenderbuffers);
+    GLESPROLOG(glGenRenderbuffers);
     
     putCmd(OPC_glGenRenderbuffers);
     putInt(n);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(n, renderbuffers);
+    ORIG(glGenRenderbuffers)(n, renderbuffers);
     uint64_t end = gethrtime();
     
     int i;
@@ -1127,18 +1177,18 @@
     }
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glGenTextures) (GLsizei n, GLuint* textures)
 {
-    GLPROLOG(glGenTextures);
+    GLESPROLOG(glGenTextures);
     
     putCmd(OPC_glGenTextures);
     putInt(n);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(n, textures);
+    ORIG(glGenTextures)(n, textures);
     uint64_t end = gethrtime();
     
     int i;
@@ -1147,18 +1197,18 @@
     }
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glGetActiveAttrib) (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name)
 {
-    GLPROLOG(glGetActiveAttrib);
+    GLESPROLOG(glGetActiveAttrib);
     NOT_IMPLEMENTED();
 }    
 
 DEF(void, glGetActiveUniform) (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name)
 {
-    GLPROLOG(glGetActiveUniform);
+    GLESPROLOG(glGetActiveUniform);
 
     putCmd(OPC_glGetActiveUniform);
     putInt(program);
@@ -1170,7 +1220,7 @@
     putPtr(name);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(program, index, bufsize, length, size, type, name);
+    ORIG(glGetActiveUniform)(program, index, bufsize, length, size, type, name);
     uint64_t end = gethrtime();
     
     if (length) putInt(*length);
@@ -1179,12 +1229,12 @@
     if (name)   putString(name);
     putTime(bgn, end);
     
-    GLEPILOG();
+    GLESEPILOG();
 }
 
 DEF(void, glGetAttachedShaders) (GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders)
 {
-    GLPROLOG(glGetAttachedShaders);
+    GLESPROLOG(glGetAttachedShaders);
     
     putCmd(OPC_glGetAttachedShaders);
     putInt(program);
@@ -1193,7 +1243,7 @@
     putPtr(shaders);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(program, maxcount, count, shaders);
+    ORIG(glGetAttachedShaders)(program, maxcount, count, shaders);
     uint64_t end = gethrtime();
 
     if (count) {
@@ -1205,90 +1255,90 @@
     }
     putTime(bgn, end);
     
-    GLEPILOG();
+    GLESEPILOG();
 }
 
 DEF(int, glGetAttribLocation) (GLuint program, const GLchar* name)
 {
-    GLPROLOG(glGetAttribLocation);
+    GLESPROLOG(glGetAttribLocation);
     
     putCmd(OPC_glGetAttribLocation);
     putInt(program);
     putString(name);
     
     uint64_t bgn = gethrtime();
-    int res = (*(int(*)())orig)(program, name);
+    int res = ORIG(glGetAttribLocation)(program, name);
     uint64_t end = gethrtime();
     
     putInt(res);
     putTime(bgn, end);
     
-    GLEPILOG();
+    GLESEPILOG();
     
     return res;
 }
 
 DEF(void, glGetBooleanv) (GLenum pname, GLboolean* params)
 {
-    GLPROLOG(glGetBooleanv);
+    GLESPROLOG(glGetBooleanv);
     
     putCmd(OPC_glGetBooleanv);
     putInt(pname);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(pname, params);
+    ORIG(glGetBooleanv)(pname, params);
     uint64_t end = gethrtime();
     
     putInt(params == NULL ? 0 : *params);
     putTime(bgn, end);
     
-    GLEPILOG();
+    GLESEPILOG();
 }
 
 DEF(void, glGetBufferParameteriv) (GLenum target, GLenum pname, GLint* params)
 {
-    GLPROLOG(glGetBufferParameteriv);
+    GLESPROLOG(glGetBufferParameteriv);
     NOT_IMPLEMENTED();
 }    
 
 DEF(GLenum, glGetError) (void)
 {
-    GLPROLOG(glGetError);
+    GLESPROLOG(glGetError);
     
     putCmd(OPC_glGetError);
     
     uint64_t bgn = gethrtime();
-    GLenum res = (*(GLenum(*)())orig)();
+    GLenum res = ORIG(glGetError)();
     uint64_t end = gethrtime();
     
     putInt(res);
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
     
     return res;
 }    
 
 DEF(void, glGetFloatv) (GLenum pname, GLfloat* params)
 {
-    GLPROLOG(glGetFloatv);
+    GLESPROLOG(glGetFloatv);
     
     putCmd(OPC_glGetFloatv);
     putInt(pname);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)(GLenum, GLfloat*))orig)(pname, params);
+    ORIG(glGetFloatv)(pname, params);
     uint64_t end = gethrtime();
     
     putFloatPtr(params);
     putTime(bgn, end);
     
-    GLEPILOG();
+    GLESEPILOG();
 }
 
 DEF(void, glGetFramebufferAttachmentParameteriv) (GLenum target, GLenum attachment, GLenum pname, GLint* params)
 {
-    GLPROLOG(glGetFramebufferAttachmentParameteriv);
+    GLESPROLOG(glGetFramebufferAttachmentParameteriv);
     
     putCmd(OPC_glGetFramebufferAttachmentParameteriv);
     putInt(target);
@@ -1296,310 +1346,314 @@
     putInt(pname);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(target, attachment, pname, params);
+    ORIG(glGetFramebufferAttachmentParameteriv)(target, attachment, pname, params);
     uint64_t end = gethrtime();
     
     putInt(params == NULL ? 0 : *params);
     putTime(bgn, end);
     
-    GLEPILOG();
+    GLESEPILOG();
 }
 
 DEF(void, glGetIntegerv) (GLenum pname, GLint* params)
 {
-    GLPROLOG(glGetIntegerv);
+    GLESPROLOG(glGetIntegerv);
     
     putCmd(OPC_glGetIntegerv);
     putInt(pname);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(pname, params);
+    ORIG(glGetIntegerv)(pname, params);
     uint64_t end = gethrtime();
     
     putIntPtr(params);
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glGetProgramiv) (GLuint program, GLenum pname, GLint* params)
 {
-    GLPROLOG(glGetProgramiv);
+    GLESPROLOG(glGetProgramiv);
     
     putCmd(OPC_glGetProgramiv);
     putInt(program);
     putInt(pname);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(program, pname, params);
+    ORIG(glGetProgramiv)(program, pname, params);
     uint64_t end = gethrtime();
     
     putInt(params == NULL ? 0 : *params);
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glGetProgramInfoLog) (GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog)
 {
-    GLPROLOG(glGetProgramInfoLog);
+    GLESPROLOG(glGetProgramInfoLog);
     NOT_IMPLEMENTED();
 }    
 
 DEF(void, glGetRenderbufferParameteriv) (GLenum target, GLenum pname, GLint* params)
 {
-    GLPROLOG(glGetRenderbufferParameteriv);
+    GLESPROLOG(glGetRenderbufferParameteriv);
     
     putCmd(OPC_glGetRenderbufferParameteriv);
     putInt(target);
     putInt(pname);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(target, pname, params);
+    ORIG(glGetRenderbufferParameteriv)(target, pname, params);
     uint64_t end = gethrtime();
     
     putInt(params == NULL ? 0 : *params);
     putTime(bgn, end);
     
-    GLEPILOG();
+    GLESEPILOG();
 }
 
- DEF(void, glGetShaderiv) (GLuint shader, GLenum pname, GLint* params)
+DEF(void, glGetShaderiv) (GLuint shader, GLenum pname, GLint* params)
 {
-    GLPROLOG(glGetShaderiv);
+    GLESPROLOG(glGetShaderiv);
     
     putCmd(OPC_glGetShaderiv);
     putInt(shader);
     putInt(pname);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(shader, pname, params);
+    ORIG(glGetShaderiv)(shader, pname, params);
     uint64_t end = gethrtime();
     
     putInt(params == NULL ? 0 : *params);
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glGetShaderInfoLog) (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog)
 {
-    GLPROLOG(glGetShaderInfoLog);
+    GLESPROLOG(glGetShaderInfoLog);
     NOT_IMPLEMENTED();
 }    
 
+#if !MACOSX
 DEF(void, glGetShaderPrecisionFormat) (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision)
 {
-    GLPROLOG(glGetShaderPrecisionFormat);
+    GLESPROLOG(glGetShaderPrecisionFormat);
     NOT_IMPLEMENTED();
 }
+#endif
 
 DEF(void, glGetShaderSource) (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source)
 {
-    GLPROLOG(glGetShaderSource);
+    GLESPROLOG(glGetShaderSource);
     NOT_IMPLEMENTED();
 }    
 
 DEF(const GLubyte*, glGetString) (GLenum name)
 {
-    GLPROLOG(glGetString);
+    GLESPROLOG(glGetString);
     
     putCmd(OPC_glGetString);
     putInt(name);
     
     uint64_t bgn = gethrtime();
-    const GLubyte* res = (*(const GLubyte*(*)())orig)(name);
+    const GLubyte* res = ORIG(glGetString)(name);
     uint64_t end = gethrtime();
     
     putString(res);
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
     
     return res;
 }    
 
 DEF(void, glGetTexParameterfv) (GLenum target, GLenum pname, GLfloat* params)
 {
-    GLPROLOG(glGetTexParameterfv);
+    GLESPROLOG(glGetTexParameterfv);
     NOT_IMPLEMENTED();
 }    
 
 DEF(void, glGetTexParameteriv) (GLenum target, GLenum pname, GLint* params)
 {
-    GLPROLOG(glGetTexParameteriv);
+    GLESPROLOG(glGetTexParameteriv);
     NOT_IMPLEMENTED();
 }
 
 DEF(void, glGetUniformfv) (GLuint program, GLint location, GLfloat* params)
 {
-    GLPROLOG(glGetUniformfv);
+    GLESPROLOG(glGetUniformfv);
     NOT_IMPLEMENTED();
 }    
 
 DEF(void, glGetUniformiv) (GLuint program, GLint location, GLint* params)
 {
-    GLPROLOG(glGetUniformiv);
+    GLESPROLOG(glGetUniformiv);
     NOT_IMPLEMENTED();
 }    
 
 DEF(int, glGetUniformLocation) (GLuint program, const GLchar* name)
 {
-    GLPROLOG(glGetUniformLocation);
+    GLESPROLOG(glGetUniformLocation);
     
     putCmd(OPC_glGetUniformLocation);
     putInt(program);
     putString(name);
     
     uint64_t bgn = gethrtime();
-    int res = (*(int(*)())orig)(program, name);
+    int res = ORIG(glGetUniformLocation)(program, name);
     uint64_t end = gethrtime();
     
     putInt(res);
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
     
     return res;
 }    
 
 DEF(void, glGetVertexAttribfv) (GLuint index, GLenum pname, GLfloat* params)
 {
-    GLPROLOG(glGetVertexAttribfv);
+    GLESPROLOG(glGetVertexAttribfv);
     NOT_IMPLEMENTED();
 }    
 
 DEF(void, glGetVertexAttribiv) (GLuint index, GLenum pname, GLint* params)
 {
-    GLPROLOG(glGetVertexAttribiv);
+    GLESPROLOG(glGetVertexAttribiv);
     NOT_IMPLEMENTED();
 }    
 
 DEF(void, glGetVertexAttribPointerv) (GLuint index, GLenum pname, GLvoid** pointer)
 {
-    GLPROLOG(glGetVertexAttribPointerv);
+    GLESPROLOG(glGetVertexAttribPointerv);
     NOT_IMPLEMENTED();
 }    
 
 DEF(void, glHint) (GLenum target, GLenum mode)
 {
-    GLPROLOG(glHint);
+    GLESPROLOG(glHint);
     NOT_IMPLEMENTED();
 }    
 
 DEF(GLboolean, glIsBuffer) (GLuint buffer)
 {
-    GLPROLOG(glIsBuffer);
+    GLESPROLOG(glIsBuffer);
     NOT_IMPLEMENTED();
 }    
 
 DEF(GLboolean, glIsEnabled) (GLenum cap)
 {
-    GLPROLOG(glIsEnabled);
+    GLESPROLOG(glIsEnabled);
     NOT_IMPLEMENTED();
 }    
 
 DEF(GLboolean, glIsFramebuffer) (GLuint framebuffer)
 {
-    GLPROLOG(glIsFramebuffer);
+    GLESPROLOG(glIsFramebuffer);
     NOT_IMPLEMENTED();
 }    
 
 DEF(GLboolean, glIsProgram) (GLuint program)
 {
-    GLPROLOG(glIsProgram);
+    GLESPROLOG(glIsProgram);
     NOT_IMPLEMENTED();
 }    
 
 DEF(GLboolean, glIsRenderbuffer) (GLuint renderbuffer)
 {
-    GLPROLOG(glIsRenderbuffer);
+    GLESPROLOG(glIsRenderbuffer);
     NOT_IMPLEMENTED();
 }    
 
 DEF(GLboolean, glIsShader) (GLuint shader)
 {
-    GLPROLOG(glIsShader);
+    GLESPROLOG(glIsShader);
     NOT_IMPLEMENTED();
 }    
 
 DEF(GLboolean, glIsTexture) (GLuint texture)
 {
-    GLPROLOG(glIsTexture);
+    GLESPROLOG(glIsTexture);
     NOT_IMPLEMENTED();
 }    
 
 DEF(void, glLineWidth) (GLfloat width)
 {
-    GLPROLOG(glLineWidth);
+    GLESPROLOG(glLineWidth);
     NOT_IMPLEMENTED();
 }    
 
 DEF(void, glLinkProgram) (GLuint program)
 {
-    GLPROLOG(glLinkProgram);
+    GLESPROLOG(glLinkProgram);
     
     putCmd(OPC_glLinkProgram);
     putInt(program);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(program);
+    ORIG(glLinkProgram)(program);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glPixelStorei) (GLenum pname, GLint param)
 {
-    GLPROLOG(glPixelStorei);
+    GLESPROLOG(glPixelStorei);
     
     putCmd(OPC_glPixelStorei);
     putInt(pname);
     putInt(param);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(pname, param);
+    ORIG(glPixelStorei)(pname, param);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glPolygonOffset) (GLfloat factor, GLfloat units)
 {
-    GLPROLOG(glPolygonOffset);
+    GLESPROLOG(glPolygonOffset);
     
     putCmd(OPC_glPolygonOffset);
     putFloat(factor);
     putFloat(units);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)(GLfloat, GLfloat))orig)(factor, units);
+    ORIG(glPolygonOffset)(factor, units);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
     
-    GLEPILOG();
+    GLESEPILOG();
 }
 
 DEF(void, glReadPixels) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels)
 {
-    GLPROLOG(glReadPixels);
+    GLESPROLOG(glReadPixels);
     NOT_IMPLEMENTED();
 }    
 
+#if !MACOSX
 DEF(void, glReleaseShaderCompiler) (void)
 {
-    GLPROLOG(glReleaseShaderCompiler);
+    GLESPROLOG(glReleaseShaderCompiler);
     NOT_IMPLEMENTED();
 }
+#endif
 
 DEF(void, glRenderbufferStorage) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
 {
-    GLPROLOG(glRenderbufferStorage);
+    GLESPROLOG(glRenderbufferStorage);
     
     putCmd(OPC_glRenderbufferStorage);
     putInt(target);
@@ -1608,23 +1662,23 @@
     putInt(height);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(target, internalformat, width, height);
+    ORIG(glRenderbufferStorage)(target, internalformat, width, height);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glSampleCoverage) (GLclampf value, GLboolean invert)
 {
-    GLPROLOG(glSampleCoverage);
+    GLESPROLOG(glSampleCoverage);
     NOT_IMPLEMENTED();
 }    
 
 DEF(void, glScissor) (GLint x, GLint y, GLsizei width, GLsizei height)
 {
-    GLPROLOG(glScissor);
+    GLESPROLOG(glScissor);
     
     putCmd(OPC_glScissor);
     putInt(x);
@@ -1633,23 +1687,23 @@
     putInt(height);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(x, y, width, height);
+    ORIG(glScissor)(x, y, width, height);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glShaderBinary) (GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length)
 {
-    GLPROLOG(glShaderBinary);
+    GLESPROLOG(glShaderBinary);
     NOT_IMPLEMENTED();
 }
 
 DEF(void, glShaderSource) (GLuint shader, GLsizei count, const GLchar** string, const GLint* length)
 {
-    GLPROLOG(glShaderSource);
+    GLESPROLOG(glShaderSource);
     
     putCmd(OPC_glShaderSource);
     putInt(shader);
@@ -1667,47 +1721,47 @@
     }
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(shader, count, string, length);
+    ORIG(glShaderSource)(shader, count, string, length);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glStencilFunc) (GLenum func, GLint ref, GLuint mask)
 {
-    GLPROLOG(glStencilFunc);
+    GLESPROLOG(glStencilFunc);
     NOT_IMPLEMENTED();
 }    
 
 DEF(void, glStencilFuncSeparate) (GLenum face, GLenum func, GLint ref, GLuint mask)
 {
-    GLPROLOG(glStencilFuncSeparate);
+    GLESPROLOG(glStencilFuncSeparate);
     NOT_IMPLEMENTED();
 }    
 
 DEF(void, glStencilMask) (GLuint mask)
 {
-    GLPROLOG(glStencilMask);
+    GLESPROLOG(glStencilMask);
     NOT_IMPLEMENTED();
 }    
 
 DEF(void, glStencilMaskSeparate) (GLenum face, GLuint mask)
 {
-    GLPROLOG(glStencilMaskSeparate);
+    GLESPROLOG(glStencilMaskSeparate);
     NOT_IMPLEMENTED();
 }    
 
 DEF(void, glStencilOp) (GLenum fail, GLenum zfail, GLenum zpass)
 {
-    GLPROLOG(glStencilOp);
+    GLESPROLOG(glStencilOp);
     NOT_IMPLEMENTED();
 }    
 
 DEF(void, glStencilOpSeparate) (GLenum face, GLenum fail, GLenum zfail, GLenum zpass)
 {
-    GLPROLOG(glStencilOpSeparate);
+    GLESPROLOG(glStencilOpSeparate);
     NOT_IMPLEMENTED();
 }    
 
@@ -1717,7 +1771,7 @@
 DEF(void, glTexImage2D) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels)
 #endif
 {
-    GLPROLOG(glTexImage2D);
+    GLESPROLOG(glTexImage2D);
     
     putCmd(OPC_glTexImage2D);
     putInt(target);
@@ -1731,29 +1785,29 @@
     putBytes(pixels, width * height * glElementSize(format, type));
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(target, level, internalformat, width, height, border, format, type, pixels);
+    ORIG(glTexImage2D)(target, level, internalformat, width, height, border, format, type, pixels);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glTexParameterf) (GLenum target, GLenum pname, GLfloat param)
 {
-    GLPROLOG(glTexParameterf);
+    GLESPROLOG(glTexParameterf);
     NOT_IMPLEMENTED();
 }    
 
 DEF(void, glTexParameterfv) (GLenum target, GLenum pname, const GLfloat* params)
 {
-    GLPROLOG(glTexParameterfv);
+    GLESPROLOG(glTexParameterfv);
     NOT_IMPLEMENTED();
 }    
 
 DEF(void, glTexParameteri) (GLenum target, GLenum pname, GLint param)
 {
-    GLPROLOG(glTexParameteri);
+    GLESPROLOG(glTexParameteri);
     
     putCmd(OPC_glTexParameteri);
     putInt(target);
@@ -1761,23 +1815,23 @@
     putInt(param);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(target, pname, param);
+    ORIG(glTexParameteri)(target, pname, param);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glTexParameteriv) (GLenum target, GLenum pname, const GLint* params)
 {
-    GLPROLOG(glTexParameteriv);
+    GLESPROLOG(glTexParameteriv);
     NOT_IMPLEMENTED();
 }    
 
 DEF(void, glTexSubImage2D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels)
 {
-    GLPROLOG(glTexSubImage2D);
+    GLESPROLOG(glTexSubImage2D);
     
     putCmd(OPC_glTexSubImage2D);
     putInt(target);
@@ -1791,34 +1845,34 @@
     putBytes(pixels, width * height * glElementSize(format, type));
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(target, level, xoffset, yoffset, width, height, format, type, pixels);
+    ORIG(glTexSubImage2D)(target, level, xoffset, yoffset, width, height, format, type, pixels);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glUniform1f) (GLint location, GLfloat x)
 {
-    GLPROLOG(glUniform1f);
+    GLESPROLOG(glUniform1f);
     
     putCmd(OPC_glUniform1f);
     putInt(location);
     putFloat(x);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)(GLint, GLfloat))orig)(location, x);
+    ORIG(glUniform1f)(location, x);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glUniform1fv) (GLint location, GLsizei count, const GLfloat* v)
 {
-    GLPROLOG(glUniform1fv);
+    GLESPROLOG(glUniform1fv);
     
     putCmd(OPC_glUniform1fv);
     putInt(location);
@@ -1826,40 +1880,40 @@
     putBytes(v, count * sizeof(GLfloat));
     
     uint64_t bgn = gethrtime();
-    (*(void(*)(GLint, GLsizei, const GLfloat*))orig)(location, count, v);
+    ORIG(glUniform1fv)(location, count, v);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
     
-    GLEPILOG();
+    GLESEPILOG();
 }
 
 DEF(void, glUniform1i) (GLint location, GLint x)
 {
-    GLPROLOG(glUniform1i);
+    GLESPROLOG(glUniform1i);
 
     putCmd(OPC_glUniform1i);
     putInt(location);
     putInt(x);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(location, x);
+    ORIG(glUniform1i)(location, x);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glUniform1iv) (GLint location, GLsizei count, const GLint* v)
 {
-    GLPROLOG(glUniform1iv);
+    GLESPROLOG(glUniform1iv);
     NOT_IMPLEMENTED();
 }    
 
 DEF(void, glUniform2f) (GLint location, GLfloat x, GLfloat y)
 {
-    GLPROLOG(glUniform2f);
+    GLESPROLOG(glUniform2f);
 
     putCmd(OPC_glUniform2f);
     putInt(location);
@@ -1867,23 +1921,23 @@
     putFloat(y);
 
     uint64_t bgn = gethrtime();
-    (*(void(*)(GLint, GLfloat, GLfloat))orig)(location, x, y);
+    ORIG(glUniform2f)(location, x, y);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glUniform2fv) (GLint location, GLsizei count, const GLfloat* v)
 {
-    GLPROLOG(glUniform2fv);
+    GLESPROLOG(glUniform2fv);
     NOT_IMPLEMENTED();
 }    
 
 DEF(void, glUniform2i) (GLint location, GLint x, GLint y)
 {
-    GLPROLOG(glUniform2i);
+    GLESPROLOG(glUniform2i);
 
     putCmd(OPC_glUniform2i);
     putInt(location);
@@ -1891,23 +1945,23 @@
     putInt(y);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(location, x, y);
+    ORIG(glUniform2i)(location, x, y);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glUniform2iv) (GLint location, GLsizei count, const GLint* v)
 {
-    GLPROLOG(glUniform2iv);
+    GLESPROLOG(glUniform2iv);
     NOT_IMPLEMENTED();
 }    
 
 DEF(void, glUniform3f) (GLint location, GLfloat x, GLfloat y, GLfloat z)
 {
-    GLPROLOG(glUniform3f);
+    GLESPROLOG(glUniform3f);
 
     putCmd(OPC_glUniform3f);
     putInt(location);
@@ -1916,23 +1970,23 @@
     putFloat(z);
 
     uint64_t bgn = gethrtime();
-    (*(void(*)(GLint, GLfloat, GLfloat, GLfloat))orig)(location, x, y, z);
+    ORIG(glUniform3f)(location, x, y, z);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glUniform3fv) (GLint location, GLsizei count, const GLfloat* v)
 {
-    GLPROLOG(glUniform3fv);
+    GLESPROLOG(glUniform3fv);
     NOT_IMPLEMENTED();
 }    
 
 DEF(void, glUniform3i) (GLint location, GLint x, GLint y, GLint z)
 {
-    GLPROLOG(glUniform3i);
+    GLESPROLOG(glUniform3i);
 
     putCmd(OPC_glUniform3i);
     putInt(location);
@@ -1941,23 +1995,23 @@
     putInt(z);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(location, x, y, z);
+    ORIG(glUniform3i)(location, x, y, z);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glUniform3iv) (GLint location, GLsizei count, const GLint* v)
 {
-    GLPROLOG(glUniform3iv);
+    GLESPROLOG(glUniform3iv);
     NOT_IMPLEMENTED();
 }    
 
 DEF(void, glUniform4f) (GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
 {
-    GLPROLOG(glUniform4f);
+    GLESPROLOG(glUniform4f);
 
     putCmd(OPC_glUniform4f);
     putInt(location);
@@ -1967,17 +2021,17 @@
     putFloat(w);
 
     uint64_t bgn = gethrtime();
-    (*(void(*)(GLint, GLfloat, GLfloat, GLfloat, GLfloat))orig)(location, x, y, z, w);
+    ORIG(glUniform4f)(location, x, y, z, w);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glUniform4fv) (GLint location, GLsizei count, const GLfloat* v)
 {
-    GLPROLOG(glUniform4fv);
+    GLESPROLOG(glUniform4fv);
 
     putCmd(OPC_glUniform4fv);
     putInt(location);
@@ -1985,17 +2039,17 @@
     putBytes(v, count * sizeof(GLfloat));
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(location, count, v);
+    ORIG(glUniform4fv)(location, count, v);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glUniform4i) (GLint location, GLint x, GLint y, GLint z, GLint w)
 {
-    GLPROLOG(glUniform4i);
+    GLESPROLOG(glUniform4i);
 
     putCmd(OPC_glUniform4i);
     putInt(location);
@@ -2005,17 +2059,17 @@
     putInt(w);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(location, x, y, z, w);
+    ORIG(glUniform4i)(location, x, y, z, w);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glUniform4iv) (GLint location, GLsizei count, const GLint* v)
 {
-    GLPROLOG(glUniform4iv);
+    GLESPROLOG(glUniform4iv);
 
     putCmd(OPC_glUniform4iv);
     putInt(location);
@@ -2023,17 +2077,17 @@
     putBytes(v, count * sizeof(GLint));
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(location, count, v);
+    ORIG(glUniform4iv)(location, count, v);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glUniformMatrix2fv) (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
 {
-    GLPROLOG(glUniformMatrix2fv);
+    GLESPROLOG(glUniformMatrix2fv);
     
     putCmd(OPC_glUniformMatrix2fv);
     putInt(location);
@@ -2042,17 +2096,17 @@
     putBytes(value, 4 * count * sizeof(GLfloat));
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(location, count, transpose, value);
+    ORIG(glUniformMatrix2fv)(location, count, transpose, value);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
     
-    GLEPILOG();
+    GLESEPILOG();
 }
 
 DEF(void, glUniformMatrix3fv) (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
 {
-    GLPROLOG(glUniformMatrix3fv);
+    GLESPROLOG(glUniformMatrix3fv);
     
     putCmd(OPC_glUniformMatrix3fv);
     putInt(location);
@@ -2061,17 +2115,17 @@
     putBytes(value, 9 * count * sizeof(GLfloat));
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(location, count, transpose, value);
+    ORIG(glUniformMatrix3fv)(location, count, transpose, value);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
     
-    GLEPILOG();
+    GLESEPILOG();
 }
 
 DEF(void, glUniformMatrix4fv) (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
 {
-    GLPROLOG(glUniformMatrix4fv);
+    GLESPROLOG(glUniformMatrix4fv);
     
     putCmd(OPC_glUniformMatrix4fv);
     putInt(location);
@@ -2080,97 +2134,97 @@
     putBytes(value, count * sizeof(GLfloat) * 16);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(location, count, transpose, value);
+    ORIG(glUniformMatrix4fv)(location, count, transpose, value);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glUseProgram) (GLuint program)
 {
-    GLPROLOG(glUseProgram);
+    GLESPROLOG(glUseProgram);
     
     putCmd(OPC_glUseProgram);
     putInt(program);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(program);
+    ORIG(glUseProgram)(program);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glValidateProgram) (GLuint program)
 {
-    GLPROLOG(glValidateProgram);
+    GLESPROLOG(glValidateProgram);
     
     putCmd(OPC_glValidateProgram);
     putInt(program);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(program);
+    ORIG(glValidateProgram)(program);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glVertexAttrib1f) (GLuint indx, GLfloat x)
 {
-    GLPROLOG(glVertexAttrib1f);
+    GLESPROLOG(glVertexAttrib1f);
     NOT_IMPLEMENTED();
 }    
 
 DEF(void, glVertexAttrib1fv) (GLuint indx, const GLfloat* values)
 {
-    GLPROLOG(glVertexAttrib1fv);
+    GLESPROLOG(glVertexAttrib1fv);
     NOT_IMPLEMENTED();
 }    
 
 DEF(void, glVertexAttrib2f) (GLuint indx, GLfloat x, GLfloat y)
 {
-    GLPROLOG(glVertexAttrib2f);
+    GLESPROLOG(glVertexAttrib2f);
     NOT_IMPLEMENTED();
 }    
 
 DEF(void, glVertexAttrib2fv) (GLuint indx, const GLfloat* values)
 {
-    GLPROLOG(glVertexAttrib2fv);
+    GLESPROLOG(glVertexAttrib2fv);
     NOT_IMPLEMENTED();
 }    
 
 DEF(void, glVertexAttrib3f) (GLuint indx, GLfloat x, GLfloat y, GLfloat z)
 {
-    GLPROLOG(glVertexAttrib3f);
+    GLESPROLOG(glVertexAttrib3f);
     NOT_IMPLEMENTED();
 }    
 
 DEF(void, glVertexAttrib3fv) (GLuint indx, const GLfloat* values)
 {
-    GLPROLOG(glVertexAttrib3fv);
+    GLESPROLOG(glVertexAttrib3fv);
     NOT_IMPLEMENTED();
 }    
 
 DEF(void, glVertexAttrib4f) (GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
 {
-    GLPROLOG(glVertexAttrib4f);
+    GLESPROLOG(glVertexAttrib4f);
     NOT_IMPLEMENTED();
 }    
 
 DEF(void, glVertexAttrib4fv) (GLuint indx, const GLfloat* values)
 {
-    GLPROLOG(glVertexAttrib4fv);
+    GLESPROLOG(glVertexAttrib4fv);
     NOT_IMPLEMENTED();
 }    
 
 DEF(void, glVertexAttribPointer) (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr)
 {
-    GLPROLOG(glVertexAttribPointer);
+    GLESPROLOG(glVertexAttribPointer);
     
     putCmd(OPC_glVertexAttribPointer);
     putInt(indx);
@@ -2186,17 +2240,17 @@
     vertexAttrib[indx].pointer = ptr;
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(indx, size, type, normalized, stride, ptr);
+    ORIG(glVertexAttribPointer)(indx, size, type, normalized, stride, ptr);
     uint64_t end = gethrtime();
 
     putTime(bgn, end);
 
-    GLEPILOG();
+    GLESEPILOG();
 }    
 
 DEF(void, glViewport) (GLint x, GLint y, GLsizei width, GLsizei height)
 {
-    GLPROLOG(glViewport);
+    GLESPROLOG(glViewport);
     
     putCmd(OPC_glViewport);
     putInt(x);
@@ -2205,10 +2259,250 @@
     putInt(height);
     
     uint64_t bgn = gethrtime();
-    (*(void(*)())orig)(x, y, width, height);
+    ORIG(glViewport)(x, y, width, height);
     uint64_t end = gethrtime();
     
     putTime(bgn, end);
 
-    GLEPILOG();
-}    
+    GLESEPILOG();
+}
+
+#if MACOSX
+/*
+ * Mac OS X extensions
+ */
+
+DEF(void, glBegin) (GLenum mode)
+{
+    GLESPROLOG(glBegin);
+    
+    putCmd(OPC_glBegin);
+    putInt(mode);
+    
+    uint64_t bgn = gethrtime();
+    ORIG(glBegin)(mode);
+    uint64_t end = gethrtime();
+    
+    putTime(bgn, end);
+    
+    GLESEPILOG();
+}
+
+DEF(void, glEnd) ()
+{
+    GLESPROLOG(glEnd);
+    putCmd(OPC_glEnd);
+    
+    uint64_t bgn = gethrtime();
+    ORIG(glEnd)();
+    uint64_t end = gethrtime();
+    
+    putTime(bgn, end);
+    
+    GLESEPILOG();
+}
+
+DEF(GLboolean, glIsRenderbufferEXT) (GLuint renderbuffer)
+{
+    GLESPROLOG(glIsRenderbufferEXT);
+    NOT_IMPLEMENTED();
+}
+
+DEF(void, glBindRenderbufferEXT) (GLenum target, GLuint renderbuffer)
+{
+    GLESPROLOG(glIsRenderbufferEXT);
+    NOT_IMPLEMENTED();
+}
+
+DEF(void, glDeleteRenderbuffersEXT) (GLsizei n, const GLuint *renderbuffers)
+{
+    GLESPROLOG(glDeleteRenderbuffersEXT);
+    NOT_IMPLEMENTED();
+}
+
+DEF(void, glGenRenderbuffersEXT) (GLsizei n, GLuint *renderbuffers)
+{
+    GLESPROLOG(glGenRenderbuffersEXT);
+    NOT_IMPLEMENTED();
+}
+
+DEF(void, glRenderbufferStorageEXT) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
+{
+    GLESPROLOG(glRenderbufferStorageEXT);
+    NOT_IMPLEMENTED();
+}
+
+DEF(void, glGetRenderbufferParameterivEXT) (GLenum target, GLenum pname, GLint *params)
+{
+    GLESPROLOG(glGetRenderbufferParameterivEXT);
+    NOT_IMPLEMENTED();
+}
+
+DEF(GLboolean, glIsFramebufferEXT) (GLuint framebuffer)
+{
+    GLESPROLOG(glIsFramebufferEXT);
+    NOT_IMPLEMENTED();
+}
+
+DEF(void, glBindFramebufferEXT) (GLenum target, GLuint framebuffer)
+{
+    GLESPROLOG(glBindFramebufferEXT);
+    
+    putCmd(OPC_glBindFramebufferEXT);
+    putInt(target);
+    putInt(framebuffer);
+    
+    uint64_t bgn = gethrtime();
+    ORIG(glBindFramebufferEXT)(target, framebuffer);
+    uint64_t end = gethrtime();
+    
+    putTime(bgn, end);
+    
+    GLESEPILOG();
+}
+
+DEF(void, glDeleteFramebuffersEXT) (GLsizei n, const GLuint *framebuffers)
+{
+    GLESPROLOG(glDeleteFramebuffersEXT);
+    NOT_IMPLEMENTED();
+}
+
+DEF(void, glGenFramebuffersEXT) (GLsizei n, GLuint *framebuffers)
+{
+    GLESPROLOG(glGenFramebuffersEXT);
+    
+    putCmd(OPC_glGenFramebuffersEXT);
+    putInt(n);
+    
+    uint64_t bgn = gethrtime();
+    ORIG(glGenFramebuffersEXT)(n, framebuffers);
+    uint64_t end = gethrtime();
+    
+    int i;
+    for (i=0; i<n; ++i) {
+        putInt(framebuffers[i]);
+    }
+    putTime(bgn, end);
+    
+    GLESEPILOG();
+}
+
+DEF(GLenum, glCheckFramebufferStatusEXT) (GLenum target)
+{
+    GLESPROLOG(glCheckFramebufferStatusEXT);
+    
+    putCmd(OPC_glCheckFramebufferStatusEXT);
+    putInt(target);
+    
+    uint64_t bgn = gethrtime();
+    GLenum res = ORIG(glCheckFramebufferStatusEXT)(target);
+    uint64_t end = gethrtime();
+    
+    putInt(res);
+    putTime(bgn, end);
+    
+    GLESEPILOG();
+    
+    return res;
+}
+
+DEF(void, glFramebufferTexture1DEXT) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
+{
+    GLESPROLOG(glFramebufferTexture1DEXT);
+    NOT_IMPLEMENTED();
+}
+
+DEF(void, glFramebufferTexture2DEXT) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
+{
+    GLESPROLOG(glFramebufferTexture2DEXT);
+    
+    putCmd(OPC_glFramebufferTexture2DEXT);
+    putInt(target);
+    putInt(attachment);
+    putInt(textarget);
+    putInt(texture);
+    putInt(level);
+    
+    uint64_t bgn = gethrtime();
+    ORIG(glFramebufferTexture2DEXT)(target, attachment, textarget, texture, level);
+    uint64_t end = gethrtime();
+    
+    putTime(bgn, end);
+    
+    GLESEPILOG();
+}
+
+DEF(void, glFramebufferTexture3DEXT) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset)
+{
+    GLESPROLOG(glFramebufferTexture3DEXT);
+    NOT_IMPLEMENTED();
+}
+
+DEF(void, glFramebufferRenderbufferEXT) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
+{
+    GLESPROLOG(glFramebufferRenderbufferEXT);
+    NOT_IMPLEMENTED();
+}
+
+DEF(void, glGetFramebufferAttachmentParameterivEXT) (GLenum target, GLenum attachment, GLenum pname, GLint *params)
+{
+    GLESPROLOG(glGetFramebufferAttachmentParameterivEXT);
+    NOT_IMPLEMENTED();
+}
+
+DEF(void, glGenerateMipmapEXT) (GLenum target)
+{
+    GLESPROLOG(glGenerateMipmapEXT);
+    NOT_IMPLEMENTED();
+}
+
+DEF(void, glGenFencesAPPLE) (GLsizei n, GLint *fences)
+{
+    GLESPROLOG(glGenFencesAPPLE);
+    NOT_IMPLEMENTED();
+}
+
+DEF(void, glDeleteFencesAPPLE) (GLsizei n, const GLint *fences)
+{
+    GLESPROLOG(glDeleteFencesAPPLE);
+    NOT_IMPLEMENTED();
+}
+
+DEF(void, glSetFenceAPPLE) (GLint fence)
+{
+    GLESPROLOG(glSetFenceAPPLE);
+    NOT_IMPLEMENTED();
+}
+
+DEF(GLboolean, glIsFenceAPPLE) (GLint fence)
+{
+    GLESPROLOG(glIsFenceAPPLE);
+    NOT_IMPLEMENTED();
+}
+
+DEF(GLboolean, glTestFenceAPPLE) (GLint fence)
+{
+    GLESPROLOG(glTestFenceAPPLE);
+    NOT_IMPLEMENTED();
+}
+
+DEF(void, glFinishFenceAPPLE) (GLint fence)
+{
+    GLESPROLOG(glFinishFenceAPPLE);
+    NOT_IMPLEMENTED();
+}
+
+DEF(GLboolean, glTestObjectAPPLE) (GLenum object, GLint name)
+{
+    GLESPROLOG(glTestObjectAPPLE);
+    NOT_IMPLEMENTED();
+}
+
+DEF(void, glFinishObjectAPPLE) (GLenum object, GLint name)
+{
+    GLESPROLOG(glFinishObjectAPPLE);
+    NOT_IMPLEMENTED();
+}
+
+#endif /* MACOSX */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/gltrace/gles.h	Tue Sep 03 09:40:03 2013 -0700
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+ 
+#ifndef GLTRACE_GLES_H
+#define GLTRACE_GLES_H
+
+
+#if linux
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include "trace.h"
+
+#define DEF(type, func) type func
+#define ORIG(func) orig_##func
+
+#define NOT_IMPLEMENTED() \
+    { \
+        fprintf(stderr, "FATAL: not implemented %s\n", __FUNCTION__); \
+        exit(1); \
+    }
+
+#define GLESPROLOG(func) \
+    static proto_##func orig_##func = NULL; \
+    if (orig_##func == NULL) { \
+        DLFCN_HOOK_POP(); \
+        orig_##func = dlsym(libGLESv2, #func); \
+        DLFCN_HOOK_PUSH(); \
+    }
+
+#define GLESEPILOG() 
+
+typedef void(*proto_glActiveTexture)(GLenum texture);
+typedef void(*proto_glAttachShader) (GLuint program, GLuint shader);
+typedef void(*proto_glBindAttribLocation) (GLuint program, GLuint index, const GLchar* name);
+typedef void(*proto_glBindBuffer) (GLenum target, GLuint buffer);
+typedef void(*proto_glBindFramebuffer) (GLenum target, GLuint framebuffer);
+typedef void(*proto_glBindRenderbuffer) (GLenum target, GLuint renderbuffer);
+typedef void(*proto_glBindTexture) (GLenum target, GLuint texture);
+typedef void(*proto_glBlendColor) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+typedef void(*proto_glBlendEquation) (GLenum mode);
+typedef void(*proto_glBlendEquationSeparate) (GLenum modeRGB, GLenum modeAlpha);
+typedef void(*proto_glBlendFunc) (GLenum sfactor, GLenum dfactor);
+typedef void(*proto_glBlendFuncSeparate) (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+typedef void(*proto_glBufferData) (GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage);
+typedef void(*proto_glBufferSubData) (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data);
+typedef GLenum(*proto_glCheckFramebufferStatus) (GLenum target);
+typedef void(*proto_glClear) (GLbitfield mask);
+typedef void(*proto_glClearColor) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+typedef void(*proto_glClearDepthf) (GLclampf depth);
+typedef void(*proto_glClearStencil) (GLint s);
+typedef void(*proto_glColorMask) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+typedef void(*proto_glCompileShader) (GLuint shader);
+typedef void(*proto_glCompressedTexImage2D) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data);
+typedef void(*proto_glCompressedTexSubImage2D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data);
+typedef void(*proto_glCopyTexImage2D) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+typedef void(*proto_glCopyTexSubImage2D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef GLuint(*proto_glCreateProgram) (void);
+typedef GLuint(*proto_glCreateShader) (GLenum type);
+typedef void(*proto_glCullFace) (GLenum mode);
+typedef void(*proto_glDeleteBuffers) (GLsizei n, const GLuint* buffers);
+typedef void(*proto_glDeleteFramebuffers) (GLsizei n, const GLuint* framebuffers);
+typedef void(*proto_glDeleteProgram) (GLuint program);
+typedef void(*proto_glDeleteRenderbuffers) (GLsizei n, const GLuint* renderbuffers);
+typedef void(*proto_glDeleteShader) (GLuint shader);
+typedef void(*proto_glDeleteTextures) (GLsizei n, const GLuint* textures);
+typedef void(*proto_glDepthFunc) (GLenum func);
+typedef void(*proto_glDepthMask) (GLboolean flag);
+typedef void(*proto_glDepthRangef) (GLclampf zNear, GLclampf zFar);
+typedef void(*proto_glDetachShader) (GLuint program, GLuint shader);
+typedef void(*proto_glDisable) (GLenum cap);
+typedef void(*proto_glDisableVertexAttribArray) (GLuint index);
+typedef void(*proto_glDrawArrays) (GLenum mode, GLint first, GLsizei count);
+typedef void(*proto_glDrawElements) (GLenum mode, GLsizei count, GLenum type, const GLvoid* indices);
+typedef void(*proto_glEnable) (GLenum cap);
+typedef void(*proto_glEnableVertexAttribArray) (GLuint index);
+typedef void(*proto_glFinish) (void);
+typedef void(*proto_glFlush) (void);
+typedef void(*proto_glFramebufferRenderbuffer) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+typedef void(*proto_glFramebufferTexture2D) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+typedef void(*proto_glFrontFace) (GLenum mode);
+typedef void(*proto_glGenBuffers) (GLsizei n, GLuint* buffers);
+typedef void(*proto_glGenerateMipmap) (GLenum target);
+typedef void(*proto_glGenFramebuffers) (GLsizei n, GLuint* framebuffers);
+typedef void(*proto_glGenRenderbuffers) (GLsizei n, GLuint* renderbuffers);
+typedef void(*proto_glGenTextures) (GLsizei n, GLuint* textures);
+typedef void(*proto_glGetActiveAttrib) (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name);
+typedef void(*proto_glGetActiveUniform) (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name);
+typedef void(*proto_glGetAttachedShaders) (GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders);
+typedef int(*proto_glGetAttribLocation) (GLuint program, const GLchar* name);
+typedef void(*proto_glGetBooleanv) (GLenum pname, GLboolean* params);
+typedef void(*proto_glGetBufferParameteriv) (GLenum target, GLenum pname, GLint* params);
+typedef GLenum(*proto_glGetError) (void);
+typedef void(*proto_glGetFloatv) (GLenum pname, GLfloat* params);
+typedef void(*proto_glGetFramebufferAttachmentParameteriv) (GLenum target, GLenum attachment, GLenum pname, GLint* params);
+typedef void(*proto_glGetIntegerv) (GLenum pname, GLint* params);
+typedef void(*proto_glGetProgramiv) (GLuint program, GLenum pname, GLint* params);
+typedef void(*proto_glGetProgramInfoLog) (GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog);
+typedef void(*proto_glGetRenderbufferParameteriv) (GLenum target, GLenum pname, GLint* params);
+typedef void(*proto_glGetShaderiv) (GLuint shader, GLenum pname, GLint* params);
+typedef void(*proto_glGetShaderInfoLog) (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog);
+typedef void(*proto_glGetShaderPrecisionFormat) (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision);
+typedef void(*proto_glGetShaderSource) (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source);
+typedef const GLubyte*(*proto_glGetString) (GLenum name);
+typedef void(*proto_glGetTexParameterfv) (GLenum target, GLenum pname, GLfloat* params);
+typedef void(*proto_glGetTexParameteriv) (GLenum target, GLenum pname, GLint* params);
+typedef void(*proto_glGetUniformfv) (GLuint program, GLint location, GLfloat* params);
+typedef void(*proto_glGetUniformiv) (GLuint program, GLint location, GLint* params);
+typedef int(*proto_glGetUniformLocation) (GLuint program, const GLchar* name);
+typedef void(*proto_glGetVertexAttribfv) (GLuint index, GLenum pname, GLfloat* params);
+typedef void(*proto_glGetVertexAttribiv) (GLuint index, GLenum pname, GLint* params);
+typedef void(*proto_glGetVertexAttribPointerv) (GLuint index, GLenum pname, GLvoid** pointer);
+typedef void(*proto_glHint) (GLenum target, GLenum mode);
+typedef GLboolean(*proto_glIsBuffer) (GLuint buffer);
+typedef GLboolean(*proto_glIsEnabled) (GLenum cap);
+typedef GLboolean(*proto_glIsFramebuffer) (GLuint framebuffer);
+typedef GLboolean(*proto_glIsProgram) (GLuint program);
+typedef GLboolean(*proto_glIsRenderbuffer) (GLuint renderbuffer);
+typedef GLboolean(*proto_glIsShader) (GLuint shader);
+typedef GLboolean(*proto_glIsTexture) (GLuint texture);
+typedef void(*proto_glLineWidth) (GLfloat width);
+typedef void(*proto_glLinkProgram) (GLuint program);
+typedef void(*proto_glPixelStorei) (GLenum pname, GLint param);
+typedef void(*proto_glPolygonOffset) (GLfloat factor, GLfloat units);
+typedef void(*proto_glReadPixels) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels);
+typedef void(*proto_glReleaseShaderCompiler) (void);
+typedef void(*proto_glRenderbufferStorage) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void(*proto_glSampleCoverage) (GLclampf value, GLboolean invert);
+typedef void(*proto_glScissor) (GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void(*proto_glShaderBinary) (GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length);
+typedef void(*proto_glShaderSource) (GLuint shader, GLsizei count, const GLchar** string, const GLint* length);
+typedef void(*proto_glStencilFunc) (GLenum func, GLint ref, GLuint mask);
+typedef void(*proto_glStencilFuncSeparate) (GLenum face, GLenum func, GLint ref, GLuint mask);
+typedef void(*proto_glStencilMask) (GLuint mask);
+typedef void(*proto_glStencilMaskSeparate) (GLenum face, GLuint mask);
+typedef void(*proto_glStencilOp) (GLenum fail, GLenum zfail, GLenum zpass);
+typedef void(*proto_glStencilOpSeparate) (GLenum face, GLenum fail, GLenum zfail, GLenum zpass);
+typedef void(*proto_glTexImage2D) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels);
+typedef void(*proto_glTexParameterf) (GLenum target, GLenum pname, GLfloat param);
+typedef void(*proto_glTexParameterfv) (GLenum target, GLenum pname, const GLfloat* params);
+typedef void(*proto_glTexParameteri) (GLenum target, GLenum pname, GLint param);
+typedef void(*proto_glTexParameteriv) (GLenum target, GLenum pname, const GLint* params);
+typedef void(*proto_glTexSubImage2D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels);
+typedef void(*proto_glUniform1f) (GLint location, GLfloat x);
+typedef void(*proto_glUniform1fv) (GLint location, GLsizei count, const GLfloat* v);
+typedef void(*proto_glUniform1i) (GLint location, GLint x);
+typedef void(*proto_glUniform1iv) (GLint location, GLsizei count, const GLint* v);
+typedef void(*proto_glUniform2f) (GLint location, GLfloat x, GLfloat y);
+typedef void(*proto_glUniform2fv) (GLint location, GLsizei count, const GLfloat* v);
+typedef void(*proto_glUniform2i) (GLint location, GLint x, GLint y);
+typedef void(*proto_glUniform2iv) (GLint location, GLsizei count, const GLint* v);
+typedef void(*proto_glUniform3f) (GLint location, GLfloat x, GLfloat y, GLfloat z);
+typedef void(*proto_glUniform3fv) (GLint location, GLsizei count, const GLfloat* v);
+typedef void(*proto_glUniform3i) (GLint location, GLint x, GLint y, GLint z);
+typedef void(*proto_glUniform3iv) (GLint location, GLsizei count, const GLint* v);
+typedef void(*proto_glUniform4f) (GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void(*proto_glUniform4fv) (GLint location, GLsizei count, const GLfloat* v);
+typedef void(*proto_glUniform4i) (GLint location, GLint x, GLint y, GLint z, GLint w);
+typedef void(*proto_glUniform4iv) (GLint location, GLsizei count, const GLint* v);
+typedef void(*proto_glUniformMatrix2fv) (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+typedef void(*proto_glUniformMatrix3fv) (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+typedef void(*proto_glUniformMatrix4fv) (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+typedef void(*proto_glUseProgram) (GLuint program);
+typedef void(*proto_glValidateProgram) (GLuint program);
+typedef void(*proto_glVertexAttrib1f) (GLuint indx, GLfloat x);
+typedef void(*proto_glVertexAttrib1fv) (GLuint indx, const GLfloat* values);
+typedef void(*proto_glVertexAttrib2f) (GLuint indx, GLfloat x, GLfloat y);
+typedef void(*proto_glVertexAttrib2fv) (GLuint indx, const GLfloat* values);
+typedef void(*proto_glVertexAttrib3f) (GLuint indx, GLfloat x, GLfloat y, GLfloat z);
+typedef void(*proto_glVertexAttrib3fv) (GLuint indx, const GLfloat* values);
+typedef void(*proto_glVertexAttrib4f) (GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void(*proto_glVertexAttrib4fv) (GLuint indx, const GLfloat* values);
+typedef void(*proto_glVertexAttribPointer) (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr);
+typedef void(*proto_glViewport) (GLint x, GLint y, GLsizei width, GLsizei height);
+
+#endif /*linux */
+
+
+#if MACOSX
+
+#include <OpenGL/gl.h>
+#include <OpenGL/glext.h>
+
+#define DEF(type, func) type gltrace_##func
+#define ORIG(func) func
+
+#define NOT_IMPLEMENTED() \
+{ \
+fprintf(stderr, "FATAL: not implemented %s\n", __FUNCTION__); \
+exit(1); \
+}
+
+#define GLESPROLOG(func)
+#define GLESEPILOG()
+
+#endif /* MACOSX */
+
+#endif /* GLTRACE_GLES_H */
--- a/tools/gltrace/iolib.c	Tue Sep 03 12:13:17 2013 -0400
+++ b/tools/gltrace/iolib.c	Tue Sep 03 09:40:03 2013 -0700
@@ -359,7 +359,7 @@
     int val = *res;
     if (val == MARKER) {
         res = (int*)curPtr;
-	curPtr += sizeof(int);
+        curPtr += sizeof(int);
         val = *res;
         if (val == 0) return NULL;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/gltrace/os-macosx.c	Tue Sep 03 09:40:03 2013 -0700
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include <mach/mach_time.h>
+
+#include "os.h"
+
+static mach_timebase_info_data_t timebase_info;
+static uint64_t start_abstime;
+
+static void init() __attribute__ ((constructor));
+static void
+init()
+{
+    mach_timebase_info(&timebase_info);
+    start_abstime = mach_absolute_time();
+}
+
+uint64_t
+gltrace_gethrtime()
+{
+        uint64_t ats = mach_absolute_time();
+        return (ats - start_abstime) * timebase_info.numer / timebase_info.denom;
+}
--- a/tools/gltrace/os.h	Tue Sep 03 12:13:17 2013 -0400
+++ b/tools/gltrace/os.h	Tue Sep 03 09:40:03 2013 -0700
@@ -31,4 +31,9 @@
 #define gethrtime gltrace_gethrtime
 uint64_t    gltrace_gethrtime();
 
+#if MACOSX
+#define MAP_POPULATE 0
+#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP PTHREAD_RECURSIVE_MUTEX_INITIALIZER
+#endif
+
 #endif /* GLTRACE_OS_H */
--- a/tools/gltrace/retrace.c	Tue Sep 03 12:13:17 2013 -0400
+++ b/tools/gltrace/retrace.c	Tue Sep 03 09:40:03 2013 -0700
@@ -32,9 +32,16 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 
+#if linux
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
 #include <EGL/egl.h>
+#endif
+
+#if MACOSX
+#include <OpenGL/gl.h>
+#include <OpenGL/glext.h>
+#endif
 
 #include "os.h"
 #include "iolib.h"
@@ -45,7 +52,6 @@
 typedef void             GLvoid;
 typedef char             GLchar;
 
-extern const char *eglEnum2str(EGLenum);
 extern const char *glEnum2str(GLenum);
 static void readPixels();
 static int  savePNG(char *fName, GLenum format, GLenum type, uint32_t width, uint32_t height, const void *data);
@@ -1996,6 +2002,142 @@
     }
 }
 
+#if MACOSX
+static void
+proc_glBegin(GLenum mode)
+{
+    if (printFlag) {
+        sb_appendStr("glBegin(");
+        sb_appendStr(glEnum2str(mode));
+        sb_appendStr(")");
+    }
+    if (execFlag) {
+        glBegin(mode);
+    }
+}
+
+static void
+proc_glEnd()
+{
+    if (printFlag) {
+        sb_appendStr("glEnd()");
+    }
+    if (execFlag) {
+        glEnd();
+    }
+}
+
+static GLboolean
+proc_glIsRenderbufferEXT(GLuint renderbuffer);
+static void
+proc_glBindRenderbufferEXT(GLenum target, GLuint renderbuffer);
+static void
+proc_glDeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers);
+static void
+proc_glGenRenderbuffersEXT(GLsizei n, GLuint *renderbuffers);
+static void
+proc_glRenderbufferStorageEXT(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+static void
+proc_glGetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params);
+static GLboolean
+proc_glIsFramebufferEXT(GLuint framebuffer);
+
+static void
+proc_glBindFramebufferEXT(GLenum target, GLuint framebuffer)
+{
+    if (printFlag) {
+        sb_appendStr("glBindFramebufferEXT(");
+        sb_appendStr(glEnum2str(target));
+        sb_appendStr(", ");
+        sb_appendInt(framebuffer);
+        sb_appendStr(")");
+    }
+    if (execFlag) {
+        glBindFramebufferEXT(target, framebuffer);
+    }
+}
+
+static void
+proc_glDeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers);
+
+static void
+proc_glGenFramebuffersEXT(GLsizei n, GLuint *_framebuffers)
+{
+    int i;
+    if (printFlag) {
+        sb_appendStr("glGenFramebuffersEXT(");
+        sb_appendInt(n);
+        sb_appendStr(", [");
+        for (i=0; i<n; ++i) {
+            if (i!=0) sb_appendStr(", ");
+            sb_appendInt(_framebuffers[i]);
+        }
+        sb_appendStr("])");
+    }
+    if (execFlag) {
+        GLuint framebuffers[n];
+        glGenFramebuffersEXT(n, framebuffers);
+        for (i=0; i<n; ++i) {
+            if (_framebuffers[i] != framebuffers[i]) {
+                fprintf(stderr, "FATAL: glGenFramebuffersEXT framebuffers mismatch\n");
+                exit(1);
+            }
+        }
+    }
+}
+
+static GLenum
+proc_glCheckFramebufferStatusEXT(GLenum target)
+{
+    GLenum res = 0;
+    if (printFlag) {
+        sb_appendStr("glCheckFramebufferStatusEXT(");
+        sb_appendStr(glEnum2str(target));
+        sb_appendStr(")");
+    }
+    if (execFlag) {
+        res = glCheckFramebufferStatusEXT(target);
+    }
+    return res;
+}
+
+static void
+proc_glFramebufferTexture1DEXT(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+
+static void
+proc_glFramebufferTexture2DEXT(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
+{
+    if (printFlag) {
+        sb_appendStr("glFramebufferTexture2DEXT(");
+        sb_appendStr(glEnum2str(target));
+        sb_appendStr(", ");
+        sb_appendStr(glEnum2str(attachment));
+        sb_appendStr(", ");
+        sb_appendStr(glEnum2str(textarget));
+        sb_appendStr(", ");
+        sb_appendInt(texture);
+        sb_appendStr(", ");
+        sb_appendInt(level);
+        sb_appendStr(")");
+    }
+    if (execFlag) {
+        glFramebufferTexture2DEXT(target, attachment, textarget, texture, level);
+    }
+}
+
+static void
+proc_glFramebufferTexture3DEXT(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+static void
+proc_glFramebufferRenderbufferEXT(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+static void
+proc_glGetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, GLenum pname, GLint *params);
+static void
+proc_glGenerateMipmapEXT(GLenum target);
+#endif /* MACOSX */
+
+#if linux
+extern const char *eglEnum2str(EGLenum);
+
 static EGLDisplay
 proc_eglGetDisplay(EGLNativeDisplayType display_id)
 {
@@ -2020,10 +2162,10 @@
         sb_appendPtr(dpy);
         sb_appendStr(", ");
         if (major) sb_appendInt(*major);
-	else sb_appendStr("(null)");
+        else sb_appendStr("(null)");
         sb_appendStr(", ");
         if (minor) sb_appendInt(*minor);
-	else sb_appendStr("(null)");
+        else sb_appendStr("(null)");
         sb_appendStr(")");
     }
     if (execFlag) {
@@ -2305,6 +2447,7 @@
 }
 
 static EGLBoolean proc_eglCopyBuffers() { return EGL_FALSE; }
+#endif
 
 static void
 process(int frames)
@@ -3158,7 +3301,69 @@
             proc_glViewport(x, y, width, height);
             break;
         }
-        
+#if MACOSX
+            case OPC_glBegin: {
+                GLenum mode = getInt();
+                proc_glBegin(mode);
+                break;
+            }
+            case OPC_glEnd:
+                proc_glEnd();
+                break;
+            case OPC_glIsRenderbufferEXT:       NOT_IMPLEMENTED();
+            case OPC_glBindRenderbufferEXT:     NOT_IMPLEMENTED();
+            case OPC_glDeleteRenderbuffersEXT:  NOT_IMPLEMENTED();
+            case OPC_glGenRenderbuffersEXT:     NOT_IMPLEMENTED();
+            case OPC_glRenderbufferStorageEXT:  NOT_IMPLEMENTED();
+            case OPC_glGetRenderbufferParameterivEXT:   NOT_IMPLEMENTED();
+            case OPC_glIsFramebufferEXT:        NOT_IMPLEMENTED();
+            case OPC_glBindFramebufferEXT: {
+                GLenum target = getInt();
+                GLuint framebuffer = getInt();
+                proc_glBindFramebufferEXT(target, framebuffer);
+                break;
+            }
+            case OPC_glDeleteFramebuffersEXT:   NOT_IMPLEMENTED();
+            case OPC_glGenFramebuffersEXT: {
+                GLsizei n = getInt();
+                GLuint framebuffers[n];
+                int i;
+                for (i=0; i<n; ++i) {
+                    framebuffers[i] = getInt();
+                }
+                proc_glGenFramebuffersEXT(n, framebuffers);
+                break;
+            }
+            case OPC_glCheckFramebufferStatusEXT: {
+                GLenum target = getInt();
+                GLenum curVal = proc_glCheckFramebufferStatusEXT(target);
+                GLenum oldVal = getInt();
+                if (printFlag) {
+                    sb_appendStr(" = ");
+                    sb_appendStr(glEnum2str(oldVal));
+                }
+                if (execFlag && curVal != oldVal) {
+                    fprintf(stderr, "ERROR: glCheckFramebufferStatusEXT return mismatch\n");
+                }
+                break;
+            }
+            case OPC_glFramebufferTexture1DEXT: NOT_IMPLEMENTED();
+            case OPC_glFramebufferTexture2DEXT: {
+                GLenum target = getInt();
+                GLenum attachment = getInt();
+                GLenum textarget = getInt();
+                GLuint texture = getInt();
+                GLint level = getInt();
+                proc_glFramebufferTexture2DEXT(target, attachment, textarget, texture, level);
+                break;
+            }
+            case OPC_glFramebufferTexture3DEXT: NOT_IMPLEMENTED();
+            case OPC_glFramebufferRenderbufferEXT:      NOT_IMPLEMENTED();
+            case OPC_glGetFramebufferAttachmentParameterivEXT:  NOT_IMPLEMENTED();
+            case OPC_glGenerateMipmapEXT:       NOT_IMPLEMENTED();
+                
+#endif /* MACOSX */
+#if linux
         case OPC_eglGetError:   NOT_IMPLEMENTED();          
         case OPC_eglGetDisplay: {
             EGLDisplay curVal = proc_eglGetDisplay((EGLNativeDisplayType)getPtr());
@@ -3174,8 +3379,8 @@
         }
         case OPC_eglInitialize: {
             EGLDisplay dpy = (EGLDisplay)getPtr();
-	    const GLint *major = getIntPtr();
-	    const GLint *minor = getIntPtr();
+            const GLint *major = getIntPtr();
+            const GLint *minor = getIntPtr();
             EGLBoolean curVal = proc_eglInitialize(dpy, major, minor);
             EGLBoolean oldVal = getInt();
             if (printFlag) {
@@ -3399,6 +3604,7 @@
             break;
         }
         case OPC_eglCopyBuffers:        NOT_IMPLEMENTED();
+#endif /*linux */
 
         case OPC_NONE:
         case OPC_EOF:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/gltrace/trace-macosx.c	Tue Sep 03 09:40:03 2013 -0700
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#define _GNU_SOURCE
+#include <dlfcn.h>
+#include <stdio.h>
+
+#include <OpenGL/gl.h>
+#include <OpenGL/glext.h>
+
+#include "os.h"
+#include "iolib.h"
+#include "trace.h"
+
+static int tLevel = trcLevel;
+
+#define INTERPOSE(func) \
+extern void gltrace_##func(); \
+void* interpose_##func[] __attribute__ ((section("__DATA, __interpose"))) = { gltrace_##func, func }
+
+INTERPOSE(glActiveTexture);
+INTERPOSE(glAttachShader);
+INTERPOSE(glBindAttribLocation);
+INTERPOSE(glBindBuffer);
+INTERPOSE(glBindFramebuffer);
+INTERPOSE(glBindRenderbuffer);
+INTERPOSE(glBindTexture);
+INTERPOSE(glBlendColor);
+INTERPOSE(glBlendEquation);
+INTERPOSE(glBlendEquationSeparate);
+INTERPOSE(glBlendFunc);
+INTERPOSE(glBlendFuncSeparate);
+INTERPOSE(glBufferData);
+INTERPOSE(glBufferSubData);
+INTERPOSE(glCheckFramebufferStatus);
+INTERPOSE(glClear);
+INTERPOSE(glClearColor);
+#if !MACOSX
+INTERPOSE(glClearDepthf);
+#endif
+INTERPOSE(glClearStencil);
+INTERPOSE(glColorMask);
+INTERPOSE(glCompileShader);
+INTERPOSE(glCompressedTexImage2D);
+INTERPOSE(glCompressedTexSubImage2D);
+INTERPOSE(glCopyTexImage2D);
+INTERPOSE(glCopyTexSubImage2D);
+INTERPOSE(glCreateProgram);
+INTERPOSE(glCreateShader);
+INTERPOSE(glCullFace);
+INTERPOSE(glDeleteBuffers);
+INTERPOSE(glDeleteFramebuffers);
+INTERPOSE(glDeleteProgram);
+INTERPOSE(glDeleteRenderbuffers);
+INTERPOSE(glDeleteShader);
+INTERPOSE(glDeleteTextures);
+INTERPOSE(glDepthFunc);
+INTERPOSE(glDepthMask);
+#if !MACOSX
+INTERPOSE(glDepthRangef);
+#endif
+INTERPOSE(glDetachShader);
+INTERPOSE(glDisable);
+INTERPOSE(glDisableVertexAttribArray);
+INTERPOSE(glDrawArrays);
+INTERPOSE(glDrawElements);
+INTERPOSE(glEnable);
+INTERPOSE(glEnableVertexAttribArray);
+INTERPOSE(glFinish);
+INTERPOSE(glFlush);
+INTERPOSE(glFramebufferRenderbuffer);
+INTERPOSE(glFramebufferTexture2D);
+INTERPOSE(glFrontFace);
+INTERPOSE(glGenBuffers);
+INTERPOSE(glGenerateMipmap);
+INTERPOSE(glGenFramebuffers);
+INTERPOSE(glGenRenderbuffers);
+INTERPOSE(glGenTextures);
+INTERPOSE(glGetActiveAttrib);
+INTERPOSE(glGetActiveUniform);
+INTERPOSE(glGetAttachedShaders);
+INTERPOSE(glGetAttribLocation);
+INTERPOSE(glGetBooleanv);
+INTERPOSE(glGetBufferParameteriv);
+INTERPOSE(glGetError);
+INTERPOSE(glGetFloatv);
+INTERPOSE(glGetFramebufferAttachmentParameteriv);
+INTERPOSE(glGetIntegerv);
+INTERPOSE(glGetProgramiv);
+INTERPOSE(glGetProgramInfoLog);
+INTERPOSE(glGetRenderbufferParameteriv);
+INTERPOSE(glGetShaderiv);
+INTERPOSE(glGetShaderInfoLog);
+#if !MACOSX
+INTERPOSE(glGetShaderPrecisionFormat);
+#endif
+INTERPOSE(glGetShaderSource);
+INTERPOSE(glGetString);
+INTERPOSE(glGetTexParameterfv);
+INTERPOSE(glGetTexParameteriv);
+INTERPOSE(glGetUniformfv);
+INTERPOSE(glGetUniformiv);
+INTERPOSE(glGetUniformLocation);
+INTERPOSE(glGetVertexAttribfv);
+INTERPOSE(glGetVertexAttribiv);
+INTERPOSE(glGetVertexAttribPointerv);
+INTERPOSE(glHint);
+INTERPOSE(glIsBuffer);
+INTERPOSE(glIsEnabled);
+INTERPOSE(glIsFramebuffer);
+INTERPOSE(glIsProgram);
+INTERPOSE(glIsRenderbuffer);
+INTERPOSE(glIsShader);
+INTERPOSE(glIsTexture);
+INTERPOSE(glLineWidth);
+INTERPOSE(glLinkProgram);
+INTERPOSE(glPixelStorei);
+INTERPOSE(glPolygonOffset);
+INTERPOSE(glReadPixels);
+#if !MACOSX
+INTERPOSE(glReleaseShaderCompiler);
+#endif
+INTERPOSE(glRenderbufferStorage);
+INTERPOSE(glSampleCoverage);
+INTERPOSE(glScissor);
+#if !MACOSX
+INTERPOSE(glShaderBinary);
+#endif
+INTERPOSE(glShaderSource);
+INTERPOSE(glStencilFunc);
+INTERPOSE(glStencilFuncSeparate);
+INTERPOSE(glStencilMask);
+INTERPOSE(glStencilMaskSeparate);
+INTERPOSE(glStencilOp);
+INTERPOSE(glStencilOpSeparate);
+INTERPOSE(glTexImage2D);
+INTERPOSE(glTexParameterf);
+INTERPOSE(glTexParameterfv);
+INTERPOSE(glTexParameteri);
+INTERPOSE(glTexParameteriv);
+INTERPOSE(glTexSubImage2D);
+INTERPOSE(glUniform1f);
+INTERPOSE(glUniform1fv);
+INTERPOSE(glUniform1i);
+INTERPOSE(glUniform1iv);
+INTERPOSE(glUniform2f);
+INTERPOSE(glUniform2fv);
+INTERPOSE(glUniform2i);
+INTERPOSE(glUniform2iv);
+INTERPOSE(glUniform3f);
+INTERPOSE(glUniform3fv);
+INTERPOSE(glUniform3i);
+INTERPOSE(glUniform3iv);
+INTERPOSE(glUniform4f);
+INTERPOSE(glUniform4fv);
+INTERPOSE(glUniform4i);
+INTERPOSE(glUniform4iv);
+INTERPOSE(glUniformMatrix2fv);
+INTERPOSE(glUniformMatrix3fv);
+INTERPOSE(glUniformMatrix4fv);
+INTERPOSE(glUseProgram);
+INTERPOSE(glValidateProgram);
+INTERPOSE(glVertexAttrib1f);
+INTERPOSE(glVertexAttrib1fv);
+INTERPOSE(glVertexAttrib2f);
+INTERPOSE(glVertexAttrib2fv);
+INTERPOSE(glVertexAttrib3f);
+INTERPOSE(glVertexAttrib3fv);
+INTERPOSE(glVertexAttrib4f);
+INTERPOSE(glVertexAttrib4fv);
+INTERPOSE(glVertexAttribPointer);
+INTERPOSE(glViewport);
+
+#if MACOSX
+INTERPOSE(glBegin);
+INTERPOSE(glEnd);
+INTERPOSE(glIsRenderbufferEXT);
+INTERPOSE(glBindRenderbufferEXT);
+INTERPOSE(glDeleteRenderbuffersEXT);
+INTERPOSE(glGenRenderbuffersEXT);
+INTERPOSE(glRenderbufferStorageEXT);
+INTERPOSE(glGetRenderbufferParameterivEXT);
+INTERPOSE(glIsFramebufferEXT);
+INTERPOSE(glBindFramebufferEXT);
+INTERPOSE(glDeleteFramebuffersEXT);
+INTERPOSE(glGenFramebuffersEXT);
+INTERPOSE(glCheckFramebufferStatusEXT);
+INTERPOSE(glFramebufferTexture1DEXT);
+INTERPOSE(glFramebufferTexture2DEXT);
+INTERPOSE(glFramebufferTexture3DEXT);
+INTERPOSE(glFramebufferRenderbufferEXT);
+INTERPOSE(glGetFramebufferAttachmentParameterivEXT);
+INTERPOSE(glGenerateMipmapEXT);
+INTERPOSE(glGenFencesAPPLE);
+INTERPOSE(glDeleteFencesAPPLE);
+INTERPOSE(glSetFenceAPPLE);
+INTERPOSE(glIsFenceAPPLE);
+INTERPOSE(glTestFenceAPPLE);
+INTERPOSE(glFinishFenceAPPLE);
+INTERPOSE(glTestObjectAPPLE);
+INTERPOSE(glFinishObjectAPPLE);
+#endif
+
+/*
+ *    Init/fini
+ */
+
+static void init() __attribute__ ((constructor));
+static void
+init()
+{
+    iolib_init(IO_WRITE, NULL);
+    if (tLevel >= dbgLevel) {
+        fprintf(stderr, "INTERPOSITION STARTED\n");
+    }
+}
+
+static void fini() __attribute__ ((destructor));
+static void fini()
+{
+    iolib_fini();    
+    if (tLevel >= dbgLevel) {
+        fprintf(stderr, "INTERPOSITION FINISHED\n");
+    }
+}
--- a/tools/gltrace/trace.h	Tue Sep 03 12:13:17 2013 -0400
+++ b/tools/gltrace/trace.h	Tue Sep 03 09:40:03 2013 -0700
@@ -40,41 +40,6 @@
 #define DLFCN_HOOK_POP()        _dlfcn_hook = dlfcn_hook_orig
 #define DLFCN_HOOK_PUSH()       _dlfcn_hook = dlfcn_hook_trace
 
-
-#define DEF(type, func) type func
-
-#define NOT_IMPLEMENTED() \
-    { \
-        fprintf(stderr, "FATAL: not implemented %s\n", __FUNCTION__); \
-        exit(1); \
-    }
-
-#define GLPROLOG(func) \
-    static void *orig = NULL;\
-    if (orig == NULL) {\
-        DLFCN_HOOK_POP(); \
-        orig = dlsym(libGLESv2, #func);\
-        DLFCN_HOOK_PUSH(); \
-        if (tLevel >= dbgLevel) {\
-            fprintf(stderr, "INTERPOSITION dlsym("#func") = %p\n", orig);\
-        }\
-    }
-
-#define GLEPILOG() 
-
-#define EGLPROLOG(func) \
-    static void *orig = NULL;\
-    if (orig == NULL) {\
-        DLFCN_HOOK_POP(); \
-        orig = dlsym(libEGL, #func);\
-        DLFCN_HOOK_PUSH(); \
-        if (tLevel >= dbgLevel) {\
-            fprintf(stderr, "INTERPOSITION dlsym("#func") = %p\n", orig);\
-        }\
-    }
-
-#define EGLEPILOG() 
-
 #endif /* linux */