changeset 7981:a56acb9d85fa

Fix to RT-26108: Implement auto-mipmap support Reviewed by flar, kcr
author Chien Yang <chien.yang@oracle.com>
date Thu, 04 Sep 2014 20:50:21 -0700
parents dbc39f3566d5
children d69d64e13c0f
files apps/toys/FX8-3DFeatures/src/fx83dfeatures/CheckerMeshViewer.java modules/graphics/src/main/java/com/sun/prism/MultiTexture.java modules/graphics/src/main/java/com/sun/prism/ResourceFactory.java modules/graphics/src/main/java/com/sun/prism/Texture.java modules/graphics/src/main/java/com/sun/prism/d3d/D3DPhongMaterial.java modules/graphics/src/main/java/com/sun/prism/d3d/D3DRTTexture.java modules/graphics/src/main/java/com/sun/prism/d3d/D3DResourceFactory.java modules/graphics/src/main/java/com/sun/prism/d3d/D3DTexture.java modules/graphics/src/main/java/com/sun/prism/es2/ES2PhongMaterial.java modules/graphics/src/main/java/com/sun/prism/es2/ES2RTTexture.java modules/graphics/src/main/java/com/sun/prism/es2/ES2ResourceFactory.java modules/graphics/src/main/java/com/sun/prism/es2/ES2Texture.java modules/graphics/src/main/java/com/sun/prism/es2/GLContext.java modules/graphics/src/main/java/com/sun/prism/impl/BaseResourceFactory.java modules/graphics/src/main/java/com/sun/prism/impl/BaseTexture.java modules/graphics/src/main/java/com/sun/prism/j2d/J2DResourceFactory.java modules/graphics/src/main/java/com/sun/prism/j2d/J2DTexture.java modules/graphics/src/main/java/com/sun/prism/null3d/DummyResourceFactory.java modules/graphics/src/main/java/com/sun/prism/null3d/DummyTexture.java modules/graphics/src/main/java/com/sun/prism/sw/SWResourceFactory.java modules/graphics/src/main/java/com/sun/prism/sw/SWTexture.java modules/graphics/src/main/native-prism-d3d/D3DGraphics.cc modules/graphics/src/main/native-prism-d3d/D3DResourceFactory.cc modules/graphics/src/main/native-prism-d3d/D3DResourceManager.cc modules/graphics/src/main/native-prism-d3d/D3DResourceManager.h modules/graphics/src/main/native-prism-es2/GLContext.c modules/graphics/src/test/java/com/sun/javafx/sg/prism/TestGraphics.java
diffstat 27 files changed, 674 insertions(+), 103 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/toys/FX8-3DFeatures/src/fx83dfeatures/CheckerMeshViewer.java	Thu Sep 04 20:50:21 2014 -0700
@@ -0,0 +1,395 @@
+/*
+ * Copyright (c) 2014, 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 java.util.Arrays;
+import javafx.animation.Interpolator;
+import javafx.animation.RotateTransition;
+import javafx.animation.Timeline;
+import javafx.application.Application;
+import javafx.event.EventHandler;
+import javafx.geometry.Point3D;
+import javafx.scene.*;
+import javafx.scene.control.Button;
+import javafx.scene.image.PixelWriter;
+import javafx.scene.image.WritableImage;
+import javafx.scene.input.KeyEvent;
+import javafx.scene.paint.Color;
+import javafx.scene.paint.PhongMaterial;
+import javafx.scene.shape.*;
+import javafx.scene.transform.Rotate;
+import javafx.stage.Stage;
+import javafx.util.Duration;
+
+public class CheckerMeshViewer extends Application {
+
+    Group root;
+    PointLight pointLight;
+    MeshView meshView;
+    TriangleMesh triMesh;
+    PhongMaterial material;
+    RotateTransition rotTrans;
+
+    int divX = 100;
+    int divY = 100;
+    boolean smooth = false;
+    int smoothGroups[];
+    float translateValue = 0.0f;
+    float rotateAngle = 0.0f;
+    float funcValue = 0.0f;
+    float resolution = 0.1f;
+    boolean texture = true;
+    boolean textureSwitch = false;
+    WritableImage diffuseMap;
+    
+    final static float meshScale = 20;
+    final static float minX = -10;
+    final static float minY = -10;
+    final static float maxX = 10;
+    final static float maxY = 10;
+
+    double getSinDivX(double x, double y) {
+        double r = Math.sqrt(x*x + y*y);
+        return funcValue * (r == 0 ? 1 : Math.sin(r) / r);
+    }
+
+    void computeMesh(int subDivX, int subDivY, float scale) {
+         final int pointSize = 3;
+        int numDivX = subDivX + 1;
+        float[] points = triMesh.getPoints().toArray(null);
+
+        // Initial points and texCoords
+        for (int y = 0; y <= subDivY; y++) {
+            float dy = (float) y / subDivY;
+            double fy = (1 - dy) * minY + dy * maxY;
+//            System.err.println("dy = " + dy + ", fy = " + fy);
+            for (int x = 0; x <= subDivX; x++) {
+                float dx = (float) x / subDivX;
+                double fx = (1 - dx) * minX + dx * maxX;
+//                System.err.println("dx = " + dx + ", fx = " + fx);
+                int index = y * numDivX * pointSize + (x * pointSize);
+//                System.err.println("point index = " + index);
+                points[index] = (float) fx * scale;
+                points[index + 1] = (float) fy * scale;
+                points[index + 2] = (float) getSinDivX(fx, fy) * scale;
+//                System.err.println("points[" + (index + 2) + " = " + points[index + 2]);
+            }
+        }
+
+        triMesh.getPoints().set(0, points, 0, points.length);
+    }
+
+    TriangleMesh buildTriangleMesh(int subDivX, int subDivY,
+            float scale) {
+
+//        System.err.println("subDivX = " + subDivX + ", subDivY = " + subDivY);
+
+        final int pointSize = 3;
+        final int texCoordSize = 2;
+        final int faceSize = 6; // 3 point indices and 3 texCoord indices per triangle
+        int numDivX = subDivX + 1;
+        int numVerts = (subDivY + 1) * numDivX;
+        float points[] = new float[numVerts * pointSize];
+        float texCoords[] = new float[numVerts * texCoordSize];
+        int faceCount = subDivX * subDivY * 2;
+        int faces[] = new int[ faceCount * faceSize]; 
+
+        // Create points and texCoords
+        for (int y = 0; y <= subDivY; y++) {
+            float dy = (float) y / subDivY;
+            double fy = (1 - dy) * minY + dy * maxY;
+//            System.err.println("dy = " + dy + ", fy = " + fy);
+            for (int x = 0; x <= subDivX; x++) {
+                float dx = (float) x / subDivX;
+                double fx = (1 - dx) * minX + dx * maxX;
+//                System.err.println("dx = " + dx + ", fx = " + fx);
+                int index = y * numDivX * pointSize + (x * pointSize);
+//                System.err.println("point index = " + index);
+                points[index] = (float) fx * scale;
+                points[index + 1] = (float) fy * scale;
+                points[index + 2] = (float) getSinDivX(fx, fy) * scale;
+                index = y * numDivX * texCoordSize + (x * texCoordSize);
+//                System.err.println("texCoord index = " + index);
+                texCoords[index] = dx * subDivX/8;
+                texCoords[index + 1] = dy * subDivY/8;
+            }
+        }
+
+        // Create faces
+        for (int y = 0; y < subDivY; y++) {
+            for (int x = 0; x < subDivX; x++) {
+                int p00 = y * numDivX + x;
+                int p01 = p00 + 1;
+                int p10 = p00 + numDivX;
+                int p11 = p10 + 1;
+                int tc00 = y * numDivX + x;
+                int tc01 = tc00 + 1;
+                int tc10 = tc00 + numDivX;
+                int tc11 = tc10 + 1;
+
+                int index = (y * subDivX * faceSize + (x * faceSize)) * 2;
+//                System.err.println("face  0 index = " + index);
+                faces[index + 0] = p00;
+                faces[index + 1] = tc00;
+                faces[index + 2] = p10;
+                faces[index + 3] = tc10;
+                faces[index + 4] = p11;
+                faces[index + 5] = tc11;
+                index += faceSize;
+//                System.err.println("face  1 index = " + index);
+                faces[index + 0] = p11;
+                faces[index + 1] = tc11;
+                faces[index + 2] = p01;
+                faces[index + 3] = tc01;
+                faces[index + 4] = p00;
+                faces[index + 5] = tc00;
+            }
+        }
+//        for(int i = 0; i < points.length; i++) {
+//            System.err.println("points[" + i + "] = " + points[i]);
+//        }
+//        for(int i = 0; i < texCoords.length; i++) {
+//            System.err.println("texCoords[" + i + "] = " + texCoords[i]);
+//        }
+//        for(int i = 0; i < faces.length; i++) {
+//            System.err.println("faces[" + i + "] = " + faces[i]);
+//        }
+        TriangleMesh triangleMesh = new TriangleMesh();
+        triangleMesh.getPoints().setAll(points);
+        triangleMesh.getTexCoords().setAll(texCoords);
+        triangleMesh.getFaces().setAll(faces);
+        smooth = false;
+        smoothGroups = new int[divX * divY * 2];
+        triangleMesh.getFaceSmoothingGroups().setAll(smoothGroups);
+        return triangleMesh;
+    }
+
+    private Scene buildScene(int width, int height, boolean depthBuffer) {
+
+        triMesh = buildTriangleMesh(divX, divY, meshScale);
+        material = new PhongMaterial();
+        material.setDiffuseMap(diffuseMap);
+        material.setDiffuseColor(Color.WHITE);
+        meshView = new MeshView(triMesh);
+        meshView.setMaterial(material);
+
+        //Set Wireframe mode
+        meshView.setDrawMode(DrawMode.FILL);
+        meshView.setCullFace(CullFace.BACK);
+
+        final Group grp1 = new Group(meshView);
+        grp1.setRotate(0);
+        grp1.setRotationAxis(Rotate.X_AXIS);
+        Group grp2 = new Group(grp1);
+        grp2.setRotate(0);
+        grp2.setRotationAxis(Rotate.X_AXIS);
+        Group grp3 = new Group(grp2);
+        grp3.setTranslateX(400);
+        grp3.setTranslateY(400);
+        grp3.setTranslateZ(10);
+
+        pointLight = new PointLight(Color.ANTIQUEWHITE);
+        pointLight.setTranslateX(300);
+        pointLight.setTranslateY(-50);
+        pointLight.setTranslateZ(-1000);
+
+        // Animate meshview
+        rotTrans = new RotateTransition(Duration.seconds(30), meshView);
+        rotTrans.setAutoReverse(true);
+        rotTrans.setAxis(new Point3D(0, 1, 0).normalize());
+        rotTrans.setInterpolator(Interpolator.EASE_BOTH);
+        rotTrans.setCycleCount(Timeline.INDEFINITE);
+        rotTrans.setByAngle(90);
+        rotTrans.play();
+        root = new Group(grp3, pointLight);
+        Scene scene = new Scene(root, width, height, depthBuffer);
+        scene.setOnKeyTyped(new EventHandler<KeyEvent>() {
+            @Override
+            public void handle(KeyEvent e) {
+                switch (e.getCharacter()) {
+                    case "[":
+                        funcValue -= resolution;
+                        if (funcValue < -20.0f) {
+                            funcValue = -20.0f;
+                        }
+                        computeMesh(divX, divY, meshScale);
+                        break;
+                    case "]":
+                        funcValue += resolution;
+                        if (funcValue > 20.0f) {
+                            funcValue = 20.0f;
+                        }
+                        computeMesh(divX, divY, meshScale);
+                        break;
+                    case "p":
+                        funcValue = 0;
+                        computeMesh(divX, divY, meshScale);
+                        break;
+                    case "i":
+                        System.err.print("i ");
+                        if (!textureSwitch) {
+                            texture = texture ? false : true;
+                        } else {
+                            textureSwitch = false;
+                        }
+                        if (texture) {
+                            material.setDiffuseMap(diffuseMap);
+                            material.setDiffuseColor(Color.WHITE);
+                        } else {
+                            material.setDiffuseMap(null);
+                            material.setBumpMap(null);
+                            material.setDiffuseColor(Color.LIGHTGRAY);
+                        }
+                        break;
+                    case "s":
+                        smooth = !smooth;
+                        if (!smooth) {
+                            Arrays.fill(smoothGroups, 0);
+                        } else {
+                            for (int i = 0; i < smoothGroups.length; i++) {
+                                smoothGroups[i] = i % 32;
+//                                System.err.println("XXX smoothGroups[" + i + "] = " + smoothGroups[i]);
+                            }
+                        }
+                        triMesh.getFaceSmoothingGroups().setAll(smoothGroups);
+                        break;
+                    case "k":
+                         System.err.print("k ");
+                         if ((texture) || (!textureSwitch)) {
+                            material.setDiffuseMap(diffuseMap);
+                            material.setBumpMap(null);
+                            material.setDiffuseColor(Color.WHITE);
+                            texture = true;
+                            textureSwitch = true;
+                        } else {
+                            material.setDiffuseMap(null);
+                            material.setBumpMap(null);
+                            material.setDiffuseColor(Color.LIGHTGRAY);
+                        }
+                        break;
+                    case "l":
+                        System.err.print("l ");
+                        boolean wireframe = meshView.getDrawMode() == DrawMode.LINE;
+                        meshView.setDrawMode(wireframe ? DrawMode.FILL : DrawMode.LINE);
+                        break;
+                    case "<":
+                        grp1.setRotate(rotateAngle -= (resolution * 5));
+                        break;
+                    case ">":
+                        grp1.setRotate(rotateAngle += (resolution * 5));
+                        break;
+                    case "/":
+                        grp3.setTranslateZ(translateValue += 5);
+                        break;
+                    case "?":
+                        grp3.setTranslateZ(translateValue -= 5);
+                        break;
+                    case "X":
+                        grp1.setRotationAxis(Rotate.X_AXIS);
+                        break;
+                    case "Y":
+                        grp1.setRotationAxis(Rotate.Y_AXIS);
+                        break;
+                    case "Z":
+                        grp1.setRotationAxis(Rotate.Z_AXIS);
+                        break;
+                    case "P":
+                        rotateAngle = 0;
+                        grp1.setRotate(rotateAngle);
+                    case "1":
+                        System.err.print("1 ");
+                        divX = 5;
+                        divY = 5;
+                        smooth = true;
+                        smoothGroups = new int[divX * divY * 2];
+                        rotateAngle = 0.0f;
+                        funcValue = 0.0f;
+                        triMesh = buildTriangleMesh(divX, divY, meshScale);
+                        meshView.setMesh(triMesh);
+                        break;
+                    case "2":
+                        System.err.print("2 ");
+                        divX = 70;
+                        divY = 70;
+                        smooth = true;
+                        smoothGroups = new int[divX * divY * 2];
+                        rotateAngle = 0.0f;
+                        funcValue = 0.0f;
+                        triMesh = buildTriangleMesh(divX, divY, meshScale);
+                        meshView.setMesh(triMesh);
+                        break;
+                    case " ":
+                        root.getChildren().add(new Button("Button"));
+                        break;
+                    case "\\":
+                        if (rotTrans.getStatus() == Timeline.Status.RUNNING) {
+                            rotTrans.pause();
+                        } else {
+                            rotTrans.play();
+                        }
+                        break;
+                }
+            }
+        });
+        return scene;
+    }
+
+    private PerspectiveCamera addCamera(Scene scene) {
+        PerspectiveCamera perspectiveCamera = new PerspectiveCamera();
+        scene.setCamera(perspectiveCamera);
+        return perspectiveCamera;
+    }
+
+    private void setArgb(PixelWriter pWriter,
+            int startX, int endX, int startY, int endY, int value) {
+        for (int x = startX; x < endX; x++) {
+            for (int y = startY; y < endY; y++) {
+                pWriter.setArgb(x, y, value);
+            }
+        }
+    }
+
+    @Override
+    public void start(Stage primaryStage) {
+        diffuseMap = new WritableImage(16,16);
+        PixelWriter pWriter = diffuseMap.getPixelWriter();
+        setArgb(pWriter, 0, 8, 0, 8, 0Xff000000);
+        setArgb(pWriter, 8, 16, 0, 8, 0Xffffffff);
+        setArgb(pWriter, 0, 8, 8, 16, 0Xffffffff);
+        setArgb(pWriter, 8, 16, 8, 16, 0Xff000000);
+
+        Scene scene = buildScene(800, 800, true);
+        scene.setFill(Color.rgb(10, 10, 40));
+        addCamera(scene);
+        primaryStage.setTitle("Checker Mesh Viewer");
+        primaryStage.setScene(scene);
+        primaryStage.show();
+    }
+
+    public static void main(String[] args) {
+        launch(args);
+    }
+}
--- a/modules/graphics/src/main/java/com/sun/prism/MultiTexture.java	Thu Sep 04 16:43:12 2014 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/MultiTexture.java	Thu Sep 04 20:50:21 2014 -0700
@@ -235,6 +235,12 @@
     }
 
     @Override
+    public boolean getUseMipmap() {
+        // TODO: MultiTexture doesn't support mipmap yet
+        return false;
+    }
+
+    @Override
     public boolean getLinearFiltering() {
         return linearFiltering;
     }
--- a/modules/graphics/src/main/java/com/sun/prism/ResourceFactory.java	Thu Sep 04 16:43:12 2014 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/ResourceFactory.java	Thu Sep 04 20:50:21 2014 -0700
@@ -70,6 +70,30 @@
                                  Texture.WrapMode wrapMode);
 
     /**
+     * Returns a new {@code Texture} containing the pixels from the given
+     * image with the indicated texture edge wrap mode.
+     * Note that the dimensions of the returned texture may be larger
+     * than those of the given image.
+     * <p>
+     * Equivalent to (but perhaps more efficient than):
+     * <pre><code>
+     *     PixelFormat format = image.getPixelFormat();
+     *     int w = image.getWidth();
+     *     int h = image.getHeight();
+     *     Texture tex = createTexture(format, usageHint, wrapMode, w, h, useMipmap);
+     *     tex.update(image, 0, 0, w, h);
+     * </code></pre>
+     *
+     * @param image the pixel data to be uploaded to the new texture
+     * @param usageHint the Dynamic vs. Static nature of the texture data
+     * @param wrapMode the desired edge behavior (clamping vs. wrapping)
+     * @param useMipmap the flag indicates should texture be created with mipmap
+     * @return a new texture
+     */
+    public Texture createTexture(Image image, Texture.Usage usageHint,
+            Texture.WrapMode wrapMode, boolean useMipmap);
+
+    /**
      * Returns a new {@code Texture} with the given format and edge wrapping
      * support.  Note that the dimensions of the returned texture may be larger
      * than those requested and the wrap mode may be a simulated version of
@@ -77,6 +101,7 @@
      *
      * @param formatHint intended pixel format of the data to be stored
      *     in this texture
+     * @param usageHint the Dynamic vs. Static nature of the texture data
      * @param wrapMode intended wrap mode to be used for the texture
      * @param w width of the content in the texture
      * @param h height of the content in the texture
@@ -89,6 +114,25 @@
                                  int w, int h);
 
     /**
+     * Returns a new {@code Texture} with the given format and edge wrapping
+     * support.  Note that the dimensions of the returned texture may be larger
+     * than those requested and the wrap mode may be a simulated version of
+     * the type requested.
+     *
+     * @param formatHint intended pixel format of the data to be stored
+     *     in this texture
+     * @param usageHint the Dynamic vs. Static nature of the texture data
+     * @param wrapMode intended wrap mode to be used for the texture
+     * @param w width of the content in the texture
+     * @param h height of the content in the texture
+     * @param useMipmap the flag indicates should texture be created with mipmap
+     * @return texture most appropriate for the given intended format, wrap
+     * mode and dimensions
+     */
+    public Texture createTexture(PixelFormat formatHint, Texture.Usage usageHint,
+            Texture.WrapMode wrapMode, int w, int h, boolean useMipmap);
+
+    /**
      * Returns a new {@code Texture} that can contain the video image as specified
      * in the provided {@code MediaFrame}. Note that padding is almost implicit
      * since this method has to accommodate the line strides of each plane. Also
@@ -118,6 +162,25 @@
     public Texture getCachedTexture(Image image, Texture.WrapMode wrapMode);
 
     /**
+     * Returns a {@code Texture} for the given image set up to use or
+     * simulate the indicated wrap mode.
+     * If no texture could be found in the cache, this method will create a
+     * new texture and put it in the cache before returning it.
+     * NOTE: the caller of this method should not hold a reference to the
+     * cached texture beyond its immediate needs since the cache may be
+     * cleared at any time.
+     *
+     * @param image the pixel data to be uploaded if the texture is new or
+     *     needs new fringe pixels to simulate a new wrap mode
+     * @param wrapMode the mode that describes the behavior for samples
+     *     outside the content 
+     * @param useMipmap the flag indicates should mipmapping be used for this
+     *     texture
+     * @return a cached texture
+     */
+    public Texture getCachedTexture(Image image, Texture.WrapMode wrapMode, boolean useMipmap);
+
+    /**
      * Returns true if the given {@code PixelFormat} is supported; otherwise
      * returns false.
      * <p>
--- a/modules/graphics/src/main/java/com/sun/prism/Texture.java	Thu Sep 04 16:43:12 2014 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/Texture.java	Thu Sep 04 20:50:21 2014 -0700
@@ -430,6 +430,13 @@
      * @return the {@code WrapMode} for this texture
      */
     public WrapMode getWrapMode();
+    
+    /**
+     * Returns the true if mipmapping is used for this texture.
+     *
+     * @return the {@code useMipmap} flag for this texture
+     */
+    public boolean getUseMipmap();
 
     /**
      * Constructs an alternate version of this {@code Texture} with an
--- a/modules/graphics/src/main/java/com/sun/prism/d3d/D3DPhongMaterial.java	Thu Sep 04 16:43:12 2014 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/d3d/D3DPhongMaterial.java	Thu Sep 04 20:50:21 2014 -0700
@@ -75,10 +75,10 @@
         maps[map.getType().ordinal()] = map;
     }
 
-    private Texture setupTexture(TextureMap map) {
+    private Texture setupTexture(TextureMap map, boolean useMipmap) {
         Image image = map.getImage();
         Texture texture = (image == null) ? null
-                : context.getResourceFactory().getCachedTexture(image, Texture.WrapMode.REPEAT);
+                : context.getResourceFactory().getCachedTexture(image, Texture.WrapMode.REPEAT, useMipmap);
         long hTexture = (texture != null) ? ((D3DTexture) texture).getNativeTextureObject() : 0;
         context.setMap(nativeHandle, map.getType().ordinal(), hTexture);
         return texture;
@@ -93,7 +93,9 @@
                     continue;
                 }
             }
-            texture = setupTexture(maps[i]);
+            // Enable mipmap if map is diffuse or self illum.
+            boolean useMipmap = (i == PhongMaterial.DIFFUSE) || (i == PhongMaterial.SELF_ILLUM);
+            texture = setupTexture(maps[i], useMipmap);
             maps[i].setTexture(texture);
             maps[i].setDirty(false);
             if (maps[i].getImage() != null && texture == null) {
--- a/modules/graphics/src/main/java/com/sun/prism/d3d/D3DRTTexture.java	Thu Sep 04 16:43:12 2014 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/d3d/D3DRTTexture.java	Thu Sep 04 20:50:21 2014 -0700
@@ -61,7 +61,7 @@
     {
         super(context, PixelFormat.INT_ARGB_PRE, wrapMode, pResource,
               physicalWidth, physicalHeight,
-              contentX, contentY, contentWidth, contentHeight, true, samples);
+              contentX, contentY, contentWidth, contentHeight, true, samples, false);
         this.opaque = false;
     }
 
--- a/modules/graphics/src/main/java/com/sun/prism/d3d/D3DResourceFactory.java	Thu Sep 04 16:43:12 2014 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/d3d/D3DResourceFactory.java	Thu Sep 04 20:50:21 2014 -0700
@@ -129,8 +129,13 @@
   
     @Override
     public D3DTexture createTexture(PixelFormat format, Usage usagehint,
-                                    WrapMode wrapMode, int w, int h)
-    {
+            WrapMode wrapMode, int w, int h) {
+        return createTexture(format, usagehint, wrapMode, w, h, false);
+    }
+
+    @Override
+    public D3DTexture createTexture(PixelFormat format, Usage usagehint,
+            WrapMode wrapMode, int w, int h, boolean useMipmap) {
         if (!isFormatSupported(format)) {
             throw new UnsupportedOperationException(
                 "Pixel format " + format +
@@ -156,7 +161,7 @@
         }
         long pResource = nCreateTexture(context.getContextHandle(),
                                         format.ordinal(), usagehint.ordinal(),
-                                        false /*isRTT*/, allocw, alloch, 0);
+                                        false /*isRTT*/, allocw, alloch, 0, useMipmap);
         if (pResource == 0L) {
             return null;
         }
@@ -166,7 +171,7 @@
         if (wrapMode != WrapMode.CLAMP_NOT_NEEDED && (w < texw || h < texh)) {
             wrapMode = wrapMode.simulatedVersion();
         }
-        return new D3DTexture(context, format, wrapMode, pResource, texw, texh, w, h);
+        return new D3DTexture(context, format, wrapMode, pResource, texw, texh, w, h, useMipmap);
     }
 
     @Override
@@ -215,7 +220,7 @@
             }
             long pResource = nCreateTexture(context.getContextHandle(),
                     texFormat.ordinal(), Usage.DYNAMIC.ordinal(),
-                    false, texWidth, texHeight, 0);
+                    false, texWidth, texHeight, 0, false);
             if (0 == pResource) {
                 return null;
             }
@@ -225,7 +230,7 @@
             WrapMode wrapMode = (texWidth < physWidth || texHeight < physHeight)
                     ? WrapMode.CLAMP_TO_EDGE_SIMULATED : WrapMode.CLAMP_TO_EDGE;
             D3DTexture tex = new D3DTexture(context, texFormat, wrapMode, pResource,
-                                            physWidth, physHeight, width, height);
+                                            physWidth, physHeight, width, height, false);
             frame.releaseFrame();
             return tex;
         }
@@ -291,7 +296,7 @@
         long pResource = nCreateTexture(context.getContextHandle(),
                                         PixelFormat.INT_ARGB_PRE.ordinal(),
                                         Usage.DEFAULT.ordinal(),
-                                        true /*isRTT*/, createw, createh, aaSamples);
+                                        true /*isRTT*/, createw, createh, aaSamples, false);
         if (pResource == 0L) {
             return null;
         }
@@ -485,7 +490,8 @@
     static native long nCreateTexture(long pContext,
                                       int format, int hint,
                                       boolean isRTT,
-                                      int width, int height, int samples);
+                                      int width, int height, int samples,
+                                      boolean useMipmap);
     static native long nCreateSwapChain(long pContext, long hwnd,
                                         boolean isVsyncEnabled);
     static native int nReleaseResource(long pContext, long resource);
--- a/modules/graphics/src/main/java/com/sun/prism/d3d/D3DTexture.java	Thu Sep 04 16:43:12 2014 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/d3d/D3DTexture.java	Thu Sep 04 20:50:21 2014 -0700
@@ -41,27 +41,17 @@
     D3DTexture(D3DContext context, PixelFormat format, WrapMode wrapMode,
                long pResource,
                int physicalWidth, int physicalHeight,
-               int contentWidth, int contentHeight)
-    {
-        this(context, format, wrapMode, pResource,
-             physicalWidth, physicalHeight,
-             contentWidth, contentHeight, false);
-    }
-
-    D3DTexture(D3DContext context, PixelFormat format, WrapMode wrapMode,
-               long pResource,
-               int physicalWidth, int physicalHeight,
                int contentWidth, int contentHeight, boolean isRTT)
     {
         this(context, format, wrapMode, pResource, physicalWidth, physicalHeight,
-                0, 0, contentWidth, contentHeight, isRTT, 0);
+                0, 0, contentWidth, contentHeight, isRTT, 0, false);
     }
 
     D3DTexture(D3DContext context, PixelFormat format, WrapMode wrapMode,
                long pResource,
                int physicalWidth, int physicalHeight,
                int contentX, int contentY, int contentWidth, int contentHeight,
-               boolean isRTT, int samples)
+               boolean isRTT, int samples, boolean useMipmap)
     {
         super(new D3DTextureResource(new D3DTextureData(context, pResource, isRTT,
                                                         physicalWidth, physicalHeight,
@@ -69,11 +59,12 @@
               format, wrapMode,
               physicalWidth, physicalHeight,
               contentX, contentY, contentWidth, contentHeight, 
-              physicalWidth, physicalHeight);
+              physicalWidth, physicalHeight, useMipmap);
     }
 
+    // TODO: We don't handle mipmap in shared texture yet.
     D3DTexture(D3DTexture sharedTex, WrapMode altMode) {
-        super(sharedTex, altMode);
+        super(sharedTex, altMode, false);
     }
 
     @Override
--- a/modules/graphics/src/main/java/com/sun/prism/es2/ES2PhongMaterial.java	Thu Sep 04 16:43:12 2014 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/es2/ES2PhongMaterial.java	Thu Sep 04 20:50:21 2014 -0700
@@ -80,10 +80,10 @@
         maps[map.getType().ordinal()] = map;
     }
 
-    private Texture setupTexture(TextureMap map) {
+    private Texture setupTexture(TextureMap map, boolean useMipmap) {
         Image image = map.getImage();
         Texture texture = (image == null) ? null
-                : context.getResourceFactory().getCachedTexture(image, Texture.WrapMode.REPEAT);
+                : context.getResourceFactory().getCachedTexture(image, Texture.WrapMode.REPEAT, useMipmap);
         return texture;
     }
 
@@ -96,7 +96,9 @@
                     continue;
                 }
             }
-            texture = setupTexture(maps[i]);
+            // Enable mipmap if map is diffuse or self illum.
+            boolean useMipmap = (i == PhongMaterial.DIFFUSE) || (i == PhongMaterial.SELF_ILLUM);
+            texture = setupTexture(maps[i], useMipmap);
             maps[i].setTexture(texture);
             maps[i].setDirty(false);
             if (maps[i].getImage() != null && texture == null) {
--- a/modules/graphics/src/main/java/com/sun/prism/es2/ES2RTTexture.java	Thu Sep 04 16:43:12 2014 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/es2/ES2RTTexture.java	Thu Sep 04 20:50:21 2014 -0700
@@ -54,7 +54,7 @@
                 physicalWidth, physicalHeight,
                 contentX, contentY,
                 contentWidth, contentHeight,
-                maxContentWidth, maxContentHeight);
+                maxContentWidth, maxContentHeight, false);
         PrismTrace.rttCreated(resource.getResource().getFboID(),
                               physicalWidth, physicalHeight,
                               PixelFormat.BYTE_BGRA_PRE.getBytesPerPixelUnit());
--- a/modules/graphics/src/main/java/com/sun/prism/es2/ES2ResourceFactory.java	Thu Sep 04 16:43:12 2014 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/es2/ES2ResourceFactory.java	Thu Sep 04 20:50:21 2014 -0700
@@ -83,7 +83,13 @@
                                  WrapMode wrapMode,
                                  int w, int h)
     {
-        return ES2Texture.create(context, formatHint, wrapMode, w, h);
+        return createTexture(formatHint, usageHint, wrapMode, w, h, false);
+    }
+
+    @Override
+    public Texture createTexture(PixelFormat formatHint, Usage usageHint,
+            WrapMode wrapMode, int w, int h, boolean useMipmap) {
+        return ES2Texture.create(context, formatHint, wrapMode, w, h, useMipmap);
     }
 
     public Texture createTexture(MediaFrame frame) {
--- a/modules/graphics/src/main/java/com/sun/prism/es2/ES2Texture.java	Thu Sep 04 16:43:12 2014 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/es2/ES2Texture.java	Thu Sep 04 20:50:21 2014 -0700
@@ -48,11 +48,11 @@
     ES2Texture(ES2Context context, ES2TextureResource<T> resource,
                PixelFormat format, WrapMode wrapMode,
                int physicalWidth, int physicalHeight,
-               int contentX, int contentY, int contentWidth, int contentHeight)
+               int contentX, int contentY, int contentWidth, int contentHeight, boolean useMipmap)
     {
         super(resource, format, wrapMode,
               physicalWidth, physicalHeight,
-              contentX, contentY, contentWidth, contentHeight);
+              contentX, contentY, contentWidth, contentHeight, useMipmap);
         this.context = context;
     }
     
@@ -60,17 +60,19 @@
                PixelFormat format, WrapMode wrapMode,
                int physicalWidth, int physicalHeight,
                int contentX, int contentY, int contentWidth, int contentHeight,
-               int maxContentWidth, int maxContentHeight)
+               int maxContentWidth, int maxContentHeight, boolean useMipmap)
     {
         super(resource, format, wrapMode,
               physicalWidth, physicalHeight,
               contentX, contentY, contentWidth, contentHeight, 
-              maxContentWidth, maxContentHeight);
+              maxContentWidth, maxContentHeight, useMipmap);
         this.context = context;
     }
 
+
+    // TODO: We don't handle mipmap in shared texture yet.
     private ES2Texture(ES2Texture sharedTex, WrapMode newMode) {
-        super(sharedTex, newMode);
+        super(sharedTex, newMode, false);
         this.context = sharedTex.context;
     }
 
@@ -96,9 +98,7 @@
     }
 
     static ES2Texture create(ES2Context context, PixelFormat format,
-                             WrapMode wrapMode,
-                             int w, int h)
-    {
+            WrapMode wrapMode, int w, int h, boolean useMipmap) {
         if (!context.getResourceFactory().isFormatSupported(format)) {
             throw new UnsupportedOperationException(
                     "Pixel format " + format
@@ -215,9 +215,8 @@
         boolean result = uploadPixels(glCtx, GLContext.GL_TEXTURE_2D, null, format,
                                       texWidth, texHeight,
                                       contentX, contentY,
-                                      0, 0, contentW, contentH, 0, true);
-
-        glCtx.texParamsMinMax(GLContext.GL_LINEAR);
+                                      0, 0, contentW, contentH, 0, true, useMipmap);
+        glCtx.texParamsMinMax(GLContext.GL_LINEAR, useMipmap);
 
         // restore previous texture objects
         glCtx.setBoundTexture(savedTex);
@@ -228,7 +227,7 @@
         return new ES2Texture(context, texRes, format, wrapMode,
                               texWidth, texHeight,
                               contentX, contentY,
-                              contentW, contentH);
+                              contentW, contentH, useMipmap);
 
     }
 
@@ -264,7 +263,7 @@
                 // Create using subWidth/subHeight then adjust content afterwards
                 ES2Texture subTex =
                     create(context, PixelFormat.BYTE_ALPHA, WrapMode.CLAMP_TO_EDGE,
-                           subWidth, subHeight);
+                           subWidth, subHeight, false);
                 if (subTex != null) {
                     tex.setTexture(subTex, index);
                 }
@@ -314,7 +313,7 @@
         boolean result = uploadPixels(context.getGLContext(), GLContext.GL_TEXTURE_2D,
                 frame, texWidth, texHeight, true);
 
-        glCtx.texParamsMinMax(GLContext.GL_LINEAR);
+        glCtx.texParamsMinMax(GLContext.GL_LINEAR, false);
 
         // restore previous texture objects
         glCtx.setBoundTexture(savedTex);
@@ -323,20 +322,16 @@
         if (result) {
             tex = new ES2Texture(context, texRes, format, WrapMode.CLAMP_TO_EDGE,
                                  texWidth, texHeight,
-                                 0, 0, frame.getWidth(), frame.getHeight());
+                                 0, 0, frame.getWidth(), frame.getHeight(), false);
         }
         frame.releaseFrame();
         return tex;
     }
 
     private static boolean uploadPixels(GLContext glCtx, int target,
-            Buffer pixels, PixelFormat format,
-            int texw, int texh,
-            int dstx, int dsty,
-            int srcx, int srcy,
-            int srcw, int srch,
-            int srcscan,
-            boolean create) {
+            Buffer pixels, PixelFormat format, int texw, int texh,
+            int dstx, int dsty, int srcx, int srcy, int srcw, int srch,
+            int srcscan, boolean create, boolean useMipmap) {
         int alignment = 1;
         int internalFormat;
         int pixelFormat;
@@ -433,7 +428,7 @@
                 // and pixelType dictate that this is a floating point texture.
                 result = glCtx.texImage2D(target, 0, GLContext.GL_RGBA,
                         texw, texh, 0,
-                        pixelFormat, pixelType, null);
+                        pixelFormat, pixelType, null, useMipmap);
             } else {
                 // Note that on desktop we can use the GL_ALPHA format to help
                 // minimize data transfer and storage costs (only 1 byte per
@@ -479,7 +474,7 @@
                 }
                 result = glCtx.texImage2D(target, 0, internalFormat,
                         texw, texh, 0,
-                        initPixelFormat, initPixelType, initBuf);
+                        initPixelFormat, initPixelType, initBuf, useMipmap);
             }
         }
         if (pixels != null) {
@@ -574,7 +569,7 @@
             }
             result = glCtx.texImage2D(target, 0, internalFormat,
                     texw, texh, 0,
-                    GLContext.GL_ALPHA, GLContext.GL_UNSIGNED_BYTE, initBuf);
+                    GLContext.GL_ALPHA, GLContext.GL_UNSIGNED_BYTE, initBuf, false);
         }
 
         if (pixels != null) {
@@ -687,11 +682,12 @@
             int contentH = getContentHeight();
             int texWidth = getPhysicalWidth();
             int texHeight = getPhysicalHeight();
+            boolean useMipmap = getUseMipmap();
             uploadPixels(glCtx, GLContext.GL_TEXTURE_2D,
                          pixels, format,
                          texWidth, texHeight,
                          contentX + dstx, contentY + dsty,
-                         srcx, srcy, srcw, srch, srcscan, false);
+                         srcx, srcy, srcw, srch, srcscan, false, useMipmap);
 
             switch (getWrapMode()) {
                 case CLAMP_TO_EDGE:
@@ -705,7 +701,7 @@
                                      pixels, format,
                                      texWidth, texHeight,
                                      contentX + contentW, contentY + dsty,
-                                     srcx + srcw-1, srcy, 1, srch, srcscan, false);
+                                     srcx + srcw-1, srcy, 1, srch, srcscan, false, useMipmap);
                     }
                     // Repeat bottom edge, if it was modified
                     if (copyL) {
@@ -713,14 +709,14 @@
                                      pixels, format,
                                      texWidth, texHeight,
                                      contentX + dstx, contentY + contentH,
-                                     srcx, srcy + srch-1, srcw, 1, srcscan, false);
+                                     srcx, srcy + srch-1, srcw, 1, srcscan, false, useMipmap);
                         // Repeat LR corner, if it was modified
                         if (copyR) {
                             uploadPixels(glCtx, GLContext.GL_TEXTURE_2D,
                                         pixels, format,
                                         texWidth, texHeight,
                                         contentX + contentW, contentY + contentH,
-                                        srcx + srcw-1, srcy + srch-1, 1, 1, srcscan, false);
+                                        srcx + srcw-1, srcy + srch-1, 1, 1, srcscan, false, useMipmap);
                         }
                     }
                     break;
@@ -736,7 +732,7 @@
                                      pixels, format,
                                      texWidth, texHeight,
                                      contentX + contentW, contentY + dsty,
-                                     srcx, srcy, 1, srch, srcscan, false);
+                                     srcx, srcy, 1, srch, srcscan, false, useMipmap);
                     }
                     // Repeat top edge on bottom, if it was modified
                     if (repeatT) {
@@ -744,14 +740,14 @@
                                      pixels, format,
                                      texWidth, texHeight,
                                      contentX + dstx, contentY + contentH,
-                                     srcx, srcy, srcw, 1, srcscan, false);
+                                     srcx, srcy, srcw, 1, srcscan, false, useMipmap);
                         // Repeat UL pixel at LR, if it was modified
                         if (repeatL) {
                             uploadPixels(glCtx, GLContext.GL_TEXTURE_2D,
                                          pixels, format,
                                          texWidth, texHeight,
                                          contentX + contentW, contentY + contentH,
-                                         srcx, srcy, 1, 1, srcscan, false);
+                                         srcx, srcy, 1, 1, srcscan, false, useMipmap);
                         }
                     }
                     break;
--- a/modules/graphics/src/main/java/com/sun/prism/es2/GLContext.java	Thu Sep 04 16:43:12 2014 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/es2/GLContext.java	Thu Sep 04 20:50:21 2014 -0700
@@ -73,7 +73,11 @@
     // Use by Texture
     final static int GL_TEXTURE_2D                = 50;
     final static int GL_TEXTURE_BINDING_2D        = 51;
-    final static int GL_LINEAR                    = 52;
+    final static int GL_NEAREST                   = 52;
+    final static int GL_LINEAR                    = 53;
+    final static int GL_NEAREST_MIPMAP_NEAREST    = 54;
+    final static int GL_LINEAR_MIPMAP_LINEAR      = 55;
+    
 
     // Use by glPixelStorei
     final static int GL_UNPACK_ALIGNMENT          = 60;
@@ -159,13 +163,13 @@
             int x, int y, int w, int h);
     private static native void nSetDepthTest(long nativeCtxInfo, boolean depthTest);
     private static native void nSetMSAA(long nativeCtxInfo, boolean msaa);
-    private static native void nTexParamsMinMax(int pname);
+    private static native void nTexParamsMinMax(int min, int max);
     private static native boolean nTexImage2D0(int target, int level, int internalFormat,
             int width, int height, int border, int format,
-            int type, Object pixels, int pixelsByteOffset);
+            int type, Object pixels, int pixelsByteOffset, boolean useMipmap);
     private static native boolean nTexImage2D1(int target, int level, int internalFormat,
             int width, int height, int border, int format,
-            int type, Object pixels, int pixelsByteOffset);
+            int type, Object pixels, int pixelsByteOffset, boolean useMipmap);
     private static native void nTexSubImage2D0(int target, int level,
             int xoffset, int yoffset, int width, int height, int format,
             int type, Object pixels, int pixelsByteOffset);
@@ -544,22 +548,28 @@
         nUseProgram(nativeCtxInfo, progid);
     }
 
-    void texParamsMinMax(int pname) {
-        nTexParamsMinMax(pname);
+    void texParamsMinMax(int pname, boolean useMipmap) {
+        int min = pname;
+        int max = pname;
+        if (useMipmap) {
+            min = (min == GLContext.GL_LINEAR) ? GLContext.GL_LINEAR_MIPMAP_LINEAR
+                    : GLContext.GL_NEAREST_MIPMAP_NEAREST;
+        }
+        nTexParamsMinMax(min, max);
     }
 
     boolean texImage2D(int target, int level, int internalFormat,
             int width, int height, int border, int format, int type,
-            java.nio.Buffer pixels) {
+            java.nio.Buffer pixels, boolean useMipmap) {
         boolean result;
         boolean direct = BufferFactory.isDirect(pixels);
         if (direct) {
             result = nTexImage2D0(target, level, internalFormat, width, height, border, format,
-                    type, pixels, BufferFactory.getDirectBufferByteOffset(pixels));
+                    type, pixels, BufferFactory.getDirectBufferByteOffset(pixels), useMipmap);
         } else {
             result = nTexImage2D1(target, level, internalFormat, width, height, border, format,
                     type, BufferFactory.getArray(pixels),
-                    BufferFactory.getIndirectBufferByteOffset(pixels));
+                    BufferFactory.getIndirectBufferByteOffset(pixels), useMipmap);
         }
         return result;
 
--- a/modules/graphics/src/main/java/com/sun/prism/impl/BaseResourceFactory.java	Thu Sep 04 16:43:12 2014 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/impl/BaseResourceFactory.java	Thu Sep 04 20:50:21 2014 -0700
@@ -42,6 +42,9 @@
         new WeakHashMap<Image,Texture>();
     private static final Map<Image,Texture> repeatTexCache =
         new WeakHashMap<Image,Texture>();
+    // Solely used by diffuse and selfillum maps in PhongMaterial for 3D rendering
+    private static final Map<Image,Texture> mipmapTexCache =
+        new WeakHashMap<Image,Texture>();
 
     // Use a WeakHashMap as it automatically removes dead objects when they're
     // collected
@@ -69,6 +72,7 @@
     protected void clearTextureCache() {
         clearTextureCache(clampTexCache);
         clearTextureCache(repeatTexCache);
+        clearTextureCache(mipmapTexCache);
     }
 
     protected void clearTextureCache(Map<Image,Texture> texCache) {
@@ -90,6 +94,7 @@
     protected void notifyReset() {
         clampTexCache.clear();
         repeatTexCache.clear();
+        mipmapTexCache.clear();
 
         // Iterate over a *copy* of the key set because listeners may remove
         // themselves during the callback
@@ -107,6 +112,7 @@
     protected void notifyReleased() {
         clampTexCache.clear();
         repeatTexCache.clear();
+        mipmapTexCache.clear();
 
         // Iterate over a *copy* of the key set because listeners may remove
         // themselves during the callback
@@ -118,16 +124,38 @@
         }
     }
 
+    static long sizeWithMipMap(int w, int h, PixelFormat format) {
+        long size = 0;
+        int bytesPerPixel = format.getBytesPerPixelUnit();
+        while (w > 1 && h > 1) {
+            size += ((long) w) * ((long) h);
+            w = (w + 1) >> 1;
+            h = (h + 1) >> 1;            
+        }
+        size += 1;
+        return size * bytesPerPixel;
+    }
+
     @Override
     public Texture getCachedTexture(Image image, WrapMode wrapMode) {
+       return  getCachedTexture(image, wrapMode, false);
+    }
+
+    @Override
+    public Texture getCachedTexture(Image image, WrapMode wrapMode, boolean useMipmap) {
         if (image == null) {
             throw new IllegalArgumentException("Image must be non-null");
         }
         Map<Image,Texture> texCache;
         if (wrapMode == WrapMode.CLAMP_TO_EDGE) {
+            // Mipmap not supported with CLAMP mode in current implementation
+            if (useMipmap) {
+                throw new IllegalArgumentException("Mipmap not supported with CLAMP mode: useMipmap = "
+                        + useMipmap + ", wrapMode = " + wrapMode);
+            }
             texCache = clampTexCache;
         } else if (wrapMode == WrapMode.REPEAT) {
-            texCache = repeatTexCache;
+            texCache = useMipmap ? mipmapTexCache : repeatTexCache;
         } else {
             throw new IllegalArgumentException("no caching for "+wrapMode);
         }
@@ -140,7 +168,9 @@
              }
          }
          int serial = image.getSerial();
-         if (tex == null) {
+
+         // Doesn't apply if useMipmap is true
+         if (!useMipmap && tex == null) {
             // Try to share a converted texture from the other cache
             Texture othertex = (wrapMode == WrapMode.REPEAT
                    ? clampTexCache
@@ -162,15 +192,19 @@
                 othertex.unlock();
             }
         }
+
         if (tex == null) {
             int w = image.getWidth();
             int h = image.getHeight();
             TextureResourcePool pool = getTextureResourcePool();
-            long size = pool.estimateTextureSize(w, h, image.getPixelFormat());
+            // Mipmap will use more memory
+            long size = useMipmap ? sizeWithMipMap(w, h, image.getPixelFormat())
+                    : pool.estimateTextureSize(w, h, image.getPixelFormat());
             if (!pool.prepareForAllocation(size)) {
                 return null;
             }
-            tex = createTexture(image, Usage.DEFAULT, wrapMode);
+
+            tex = createTexture(image, Usage.DEFAULT, wrapMode, useMipmap);
             if (tex != null) {
                 tex.setLastImageSerial(serial);
                 texCache.put(image, tex);
@@ -183,14 +217,18 @@
     }
 
     @Override
-    public Texture createTexture(Image image,
-                                 Usage usageHint,
-                                 WrapMode wrapMode)
-    {
+    public Texture createTexture(Image image, Usage usageHint, WrapMode wrapMode) {
+        return createTexture(image, usageHint, wrapMode, false);
+    }
+
+    @Override
+    public Texture createTexture(Image image, Usage usageHint, WrapMode wrapMode,
+            boolean useMipmap) {
         PixelFormat format = image.getPixelFormat();
         int w = image.getWidth();
         int h = image.getHeight();
-        Texture tex = createTexture(format, usageHint, wrapMode, w, h);
+
+        Texture tex = createTexture(format, usageHint, wrapMode, w, h, useMipmap);
         // creation of a texture does not require flushing the vertex buffer
         // since there are no pending vertices that depend on this new texture,
         // so pass skipFlush=true here...
--- a/modules/graphics/src/main/java/com/sun/prism/impl/BaseTexture.java	Thu Sep 04 16:43:12 2014 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/impl/BaseTexture.java	Thu Sep 04 20:50:21 2014 -0700
@@ -50,10 +50,11 @@
     // We do not provide a default wrapMode because it is so dependent on
     // how the texture will be used.
     private final WrapMode wrapMode;
+    private final boolean useMipmap;
     private boolean linearFiltering = true;
     private int lastImageSerial;
 
-    protected BaseTexture(BaseTexture<T> sharedTex, WrapMode newMode) {
+    protected BaseTexture(BaseTexture<T> sharedTex, WrapMode newMode, boolean useMipmap) {
         this.resource = sharedTex.resource;
         this.format = sharedTex.format;
         this.wrapMode = newMode;
@@ -65,20 +66,21 @@
         this.contentHeight = sharedTex.contentHeight;
         this.maxContentWidth = sharedTex.maxContentWidth;
         this.maxContentHeight = sharedTex.maxContentHeight;
+        this.useMipmap = useMipmap;
     }
 
     protected BaseTexture(T resource,
                           PixelFormat format, WrapMode wrapMode,
                           int width, int height)
     {
-        this(resource, format, wrapMode, width, height, 0, 0, width, height);
+        this(resource, format, wrapMode, width, height, 0, 0, width, height, false);
     }
 
     protected BaseTexture(T resource,
                           PixelFormat format, WrapMode wrapMode,
                           int physicalWidth, int physicalHeight,
                           int contentX, int contentY,
-                          int contentWidth, int contentHeight)
+                          int contentWidth, int contentHeight, boolean useMipmap)
     {
         this.resource = resource;
         this.format = format;
@@ -91,6 +93,7 @@
         this.contentHeight = contentHeight;
         this.maxContentWidth = physicalWidth;
         this.maxContentHeight = physicalHeight;
+        this.useMipmap = useMipmap;
     }
     
     protected BaseTexture(T resource,
@@ -98,7 +101,7 @@
                           int physicalWidth, int physicalHeight,
                           int contentX, int contentY,
                           int contentWidth, int contentHeight,
-                          int maxContentWidth, int maxContentHeight)
+                          int maxContentWidth, int maxContentHeight, boolean useMipmap)
     {
         this.resource = resource;
         this.format = format;
@@ -111,6 +114,7 @@
         this.contentHeight = contentHeight;
         this.maxContentWidth = maxContentWidth;
         this.maxContentHeight = maxContentHeight;
+        this.useMipmap = useMipmap;
     }
 
     @Override
@@ -182,6 +186,11 @@
     }
 
     @Override
+    public boolean getUseMipmap() {
+        return useMipmap;
+    }
+
+    @Override
     public Texture getSharedTexture(WrapMode altMode) {
         assertLocked();
         if (wrapMode == altMode) {
--- a/modules/graphics/src/main/java/com/sun/prism/j2d/J2DResourceFactory.java	Thu Sep 04 16:43:12 2014 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/j2d/J2DResourceFactory.java	Thu Sep 04 20:50:21 2014 -0700
@@ -115,6 +115,11 @@
         return J2DTexture.create(formatHint, wrapMode, w, h);
     }
 
+    public Texture createTexture(PixelFormat formatHint,
+            Usage usageHint, WrapMode wrapMode, int w, int h, boolean useMipmap) {
+        return createTexture(formatHint, usageHint, wrapMode, w, h);
+    }
+
     public Texture createTexture(MediaFrame vdb) {
         Texture tex;
 
--- a/modules/graphics/src/main/java/com/sun/prism/j2d/J2DTexture.java	Thu Sep 04 16:43:12 2014 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/j2d/J2DTexture.java	Thu Sep 04 20:50:21 2014 -0700
@@ -101,7 +101,7 @@
     }
 
     J2DTexture(J2DTexture sharedTex, WrapMode altMode) {
-        super(sharedTex, altMode);
+        super(sharedTex, altMode, false);
         this.setter = sharedTex.setter;
     }
 
--- a/modules/graphics/src/main/java/com/sun/prism/null3d/DummyResourceFactory.java	Thu Sep 04 16:43:12 2014 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/null3d/DummyResourceFactory.java	Thu Sep 04 20:50:21 2014 -0700
@@ -69,6 +69,12 @@
         return new DummyTexture(context, format, wrapMode, w, h);
     }
 
+    @Override
+    public DummyTexture createTexture(PixelFormat format, Usage usagehint,
+            WrapMode wrapMode, int w, int h, boolean useMipmap) {
+        return createTexture(format, usagehint, wrapMode, w, h);
+    }
+
     public int getRTTWidth(int w, WrapMode wrapMode) {
         return w;
     }
--- a/modules/graphics/src/main/java/com/sun/prism/null3d/DummyTexture.java	Thu Sep 04 16:43:12 2014 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/null3d/DummyTexture.java	Thu Sep 04 20:50:21 2014 -0700
@@ -53,7 +53,7 @@
     {
         super(new DummyManagedResource(), format, wrapMode,
               contentWidth, contentHeight,
-              0, 0, contentWidth, contentHeight);
+              0, 0, contentWidth, contentHeight, false);
 
         this.context = context;
 
--- a/modules/graphics/src/main/java/com/sun/prism/sw/SWResourceFactory.java	Thu Sep 04 16:43:12 2014 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/sw/SWResourceFactory.java	Thu Sep 04 20:50:21 2014 -0700
@@ -170,6 +170,11 @@
         return SWTexture.create(this, formatHint, wrapMode, w, h);
     }
 
+    @Override public Texture createTexture(PixelFormat formatHint, Usage usageHint,
+            WrapMode wrapMode, int w, int h, boolean useMipmap) {
+        return createTexture(formatHint, usageHint, wrapMode, w, h);
+    }
+
     public PhongMaterial createPhongMaterial() {
         throw new UnsupportedOperationException("Not supported yet.");
 }
--- a/modules/graphics/src/main/java/com/sun/prism/sw/SWTexture.java	Thu Sep 04 16:43:12 2014 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/sw/SWTexture.java	Thu Sep 04 20:50:21 2014 -0700
@@ -221,6 +221,12 @@
         return wrapMode;
     }
 
+    @Override
+    public boolean getUseMipmap() {
+        // TODO: Currently mipmapping not support for software texture
+        return false;
+    }
+
     public Texture getSharedTexture(WrapMode altMode) {
         assertLocked();
         if (wrapMode == altMode) {
--- a/modules/graphics/src/main/native-prism-d3d/D3DGraphics.cc	Thu Sep 04 16:43:12 2014 -0400
+++ b/modules/graphics/src/main/native-prism-d3d/D3DGraphics.cc	Thu Sep 04 20:50:21 2014 -0700
@@ -441,6 +441,7 @@
         D3DTEXTUREFILTERTYPE fhint = linear ? D3DTEXF_LINEAR : D3DTEXF_POINT;
         pd3dDevice->SetSamplerState(texUnit, D3DSAMP_MAGFILTER, fhint);
         pd3dDevice->SetSamplerState(texUnit, D3DSAMP_MINFILTER, fhint);
+        pd3dDevice->SetSamplerState(texUnit, D3DSAMP_MIPFILTER, fhint);
         if (wrapMode != 0) {
             pd3dDevice->SetSamplerState(texUnit, D3DSAMP_ADDRESSU, wrapMode);
             pd3dDevice->SetSamplerState(texUnit, D3DSAMP_ADDRESSV, wrapMode);
--- a/modules/graphics/src/main/native-prism-d3d/D3DResourceFactory.cc	Thu Sep 04 16:43:12 2014 -0400
+++ b/modules/graphics/src/main/native-prism-d3d/D3DResourceFactory.cc	Thu Sep 04 20:50:21 2014 -0700
@@ -65,11 +65,11 @@
 Java_com_sun_prism_d3d_D3DResourceFactory_nCreateTexture
   (JNIEnv *env, jclass klass,
         jlong ctx, jint formatHint, jint usageHint, jboolean isRTT,
-        jint width, jint height, jint samples)
+        jint width, jint height, jint samples, jboolean useMipmap)
 {
     TraceLn5(NWT_TRACE_INFO,
-             "nCreateTexture formatHint=%d usageHint=%d isRTT=%d w=%d h=%d",
-             formatHint, usageHint, isRTT, width, height);
+             "nCreateTexture formatHint=%d usageHint=%d isRTT=%d w=%d h=%d useMipmap=%d",
+             formatHint, usageHint, isRTT, width, height, useMipmap);
 
     D3DContext *pCtx = (D3DContext *)jlong_to_ptr(ctx);
     RETURN_STATUS_IF_NULL(pCtx, 0L);
@@ -121,7 +121,7 @@
         res = pMgr->CreateRenderTarget(width, height, isOpaque,
                 &format, msType, &pTexResource);
     } else {
-        res = pMgr->CreateTexture(width, height, isRTT, isOpaque,
+        res = pMgr->CreateTexture(width, height, isRTT, isOpaque, useMipmap,
                 &format, dwUsage, &pTexResource);
     }
     if (SUCCEEDED(res)) {
--- a/modules/graphics/src/main/native-prism-d3d/D3DResourceManager.cc	Thu Sep 04 16:43:12 2014 -0400
+++ b/modules/graphics/src/main/native-prism-d3d/D3DResourceManager.cc	Thu Sep 04 20:50:21 2014 -0700
@@ -322,7 +322,7 @@
 
 HRESULT
 D3DResourceManager::CreateTexture(UINT width, UINT height,
-                                  BOOL isRTT, BOOL isOpaque, /*BOOL autoMipMap,*/
+                                  BOOL isRTT, BOOL isOpaque, BOOL useMipmap,
                                   D3DFORMAT *pFormat, DWORD dwUsage,
                                   D3DResource **ppTextureResource)
 {
@@ -331,7 +331,7 @@
                 width, height, isRTT, isOpaque);
 
     IDirect3DDevice9 *pd3dDevice = pCtx->Get3DDevice();
-
+       
     if (pd3dDevice == NULL) {
         return E_FAIL;
     }
@@ -379,9 +379,9 @@
         }
     }
 
-    // if (pool == D3DPOOL_MANAGED && !isDynamic && autoMipMap) {
-    //     dwUsage |= D3DUSAGE_AUTOGENMIPMAP;
-    // }
+    if (useMipmap) {
+         dwUsage |= D3DUSAGE_AUTOGENMIPMAP;
+     }
 
     IDirect3DTexture9 *pTexture = NULL;
     HRESULT res = pd3dDevice->CreateTexture(width, height, 1/*levels*/, dwUsage,
--- a/modules/graphics/src/main/native-prism-d3d/D3DResourceManager.h	Thu Sep 04 16:43:12 2014 -0400
+++ b/modules/graphics/src/main/native-prism-d3d/D3DResourceManager.h	Thu Sep 04 20:50:21 2014 -0700
@@ -192,7 +192,7 @@
     HRESULT ReleaseResource(IManagedResource* pResource);
 
     HRESULT CreateTexture(UINT width, UINT height,
-                          BOOL isRTT, BOOL isOpaque, /* BOOL autoMipMap, */
+                          BOOL isRTT, BOOL isOpaque, BOOL useMipmap,
                           D3DFORMAT *pFormat/*in/out*/,
                           DWORD dwUsage,
                           D3DResource **ppTextureResource/*out*/);
--- a/modules/graphics/src/main/native-prism-es2/GLContext.c	Thu Sep 04 16:43:12 2014 -0400
+++ b/modules/graphics/src/main/native-prism-es2/GLContext.c	Thu Sep 04 20:50:21 2014 -0700
@@ -925,8 +925,14 @@
             return GL_TEXTURE_2D;
         case com_sun_prism_es2_GLContext_GL_TEXTURE_BINDING_2D:
             return GL_TEXTURE_BINDING_2D;
+        case com_sun_prism_es2_GLContext_GL_NEAREST:
+            return GL_NEAREST;
         case com_sun_prism_es2_GLContext_GL_LINEAR:
             return GL_LINEAR;
+        case com_sun_prism_es2_GLContext_GL_NEAREST_MIPMAP_NEAREST:
+            return GL_NEAREST_MIPMAP_NEAREST;
+        case com_sun_prism_es2_GLContext_GL_LINEAR_MIPMAP_LINEAR:
+            return GL_LINEAR_MIPMAP_LINEAR;
 
         case com_sun_prism_es2_GLContext_WRAPMODE_REPEAT:
             return GL_REPEAT;
@@ -1072,9 +1078,10 @@
  * Signature: (I)V
  */
 JNIEXPORT void JNICALL Java_com_sun_prism_es2_GLContext_nTexParamsMinMax
-(JNIEnv *env, jclass class, jint pname) {
-    GLenum param = translatePrismToGL(pname);
+(JNIEnv *env, jclass class, jint min, jint max) {
+    GLenum param = translatePrismToGL(max);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, param);
+    param = translatePrismToGL(min);    
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, param);
 }
 
@@ -1086,7 +1093,7 @@
 JNIEXPORT jboolean JNICALL Java_com_sun_prism_es2_GLContext_nTexImage2D0
 (JNIEnv *env, jclass class, jint target, jint level, jint internalFormat,
         jint width, jint height, jint border, jint format, jint type,
-        jobject pixels, jint pixelsByteOffset) {
+        jobject pixels, jint pixelsByteOffset, jboolean useMipmap) {
     GLvoid *ptr = NULL;
     GLenum err;
 
@@ -1096,6 +1103,9 @@
     }
 
     glGetError();
+    if (useMipmap) {
+        glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
+    }
     glTexImage2D((GLenum) translatePrismToGL(target), (GLint) level,
             (GLint) translatePrismToGL(internalFormat),
             (GLsizei) width, (GLsizei) height, (GLint) border,
@@ -1115,7 +1125,7 @@
 JNIEXPORT jboolean JNICALL Java_com_sun_prism_es2_GLContext_nTexImage2D1
 (JNIEnv *env, jclass class, jint target, jint level, jint internalFormat,
         jint width, jint height, jint border, jint format, jint type,
-        jobject pixels, jint pixelsByteOffset) {
+        jobject pixels, jint pixelsByteOffset, jboolean useMipmap) {
     GLvoid *ptr = NULL;
     GLenum err;
 
@@ -1125,6 +1135,9 @@
     }
 
     glGetError();
+    if (useMipmap) {
+        glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
+    }
     glTexImage2D((GLenum) translatePrismToGL(target), (GLint) level,
             (GLint) translatePrismToGL(internalFormat),
             (GLsizei) width, (GLsizei) height, (GLint) border,
--- a/modules/graphics/src/test/java/com/sun/javafx/sg/prism/TestGraphics.java	Thu Sep 04 16:43:12 2014 -0400
+++ b/modules/graphics/src/test/java/com/sun/javafx/sg/prism/TestGraphics.java	Thu Sep 04 20:50:21 2014 -0700
@@ -176,11 +176,14 @@
         @Override public boolean isDeviceReady() { return true; }
 
         @Override public TextureResourcePool getTextureResourcePool() { return null; }
-        @Override public Texture createTexture(Image image, Texture.Usage usageHint, Texture.WrapMode wrapMode) { return null; }
-        @Override public Texture createTexture(PixelFormat formatHint, Texture.Usage usageHint, Texture.WrapMode wrapMode, int w, int h) { return null; }
+        @Override public Texture createTexture(Image image, Texture.Usage usageHint, WrapMode wrapMode) { return null; }
+        @Override public Texture createTexture(Image image, Texture.Usage usageHint, Texture.WrapMode wrapMode, boolean useMipmap) { return null; }
+        @Override public Texture createTexture(PixelFormat formatHint, Texture.Usage usageHint, WrapMode wrapMode, int w, int h) { return null; }
+        @Override public Texture createTexture(PixelFormat formatHint, Texture.Usage usageHint, Texture.WrapMode wrapMode, int w, int h, boolean useMipmap) { return null; }
         @Override public Texture createTexture(MediaFrame frame) { return null; }
         @Override public boolean isCompatibleTexture(Texture tex) { return true; }
         @Override public Texture getCachedTexture(Image image, WrapMode wrapMode) { return null; }
+        @Override public Texture getCachedTexture(Image image, WrapMode wrapMode, boolean useMipmap) { return null; }
         @Override public boolean isFormatSupported(PixelFormat format) { return false; }
         @Override public int getMaximumTextureSize() { return 0; }
         @Override public Texture createMaskTexture(int width, int height, Texture.WrapMode wrapMode) { return null; }
@@ -237,6 +240,7 @@
                 @Override public int getMaxContentHeight() { return getPhysicalHeight(); }
                 @Override public void setContentWidth(int contentWidth) { }
                 @Override public void setContentHeight(int contentHeight) { }
+                @Override public boolean getUseMipmap() { return false; }
             };
         }
         @Override public Presentable createPresentable(PresentableState pstate) { return null; }