1 /*
   2  * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.java2d.opengl;
  27 
  28 import java.awt.GradientPaint;
  29 import java.awt.LinearGradientPaint;
  30 import java.awt.MultipleGradientPaint;
  31 import java.awt.MultipleGradientPaint.ColorSpaceType;
  32 import java.awt.MultipleGradientPaint.CycleMethod;
  33 import java.awt.RadialGradientPaint;
  34 import java.awt.TexturePaint;
  35 import java.awt.image.BufferedImage;
  36 import java.util.HashMap;
  37 import java.util.Map;
  38 import sun.java2d.SunGraphics2D;
  39 import sun.java2d.SurfaceData;
  40 import sun.java2d.loops.CompositeType;
  41 import static sun.java2d.pipe.BufferedPaints.*;
  42 import static sun.java2d.opengl.OGLContext.OGLContextCaps.*;
  43 
  44 abstract class OGLPaints {
  45 
  46     /**
  47      * Holds all registered implementations, using the corresponding
  48      * SunGraphics2D.PAINT_* constant as the hash key.
  49      */
  50     private static Map<Integer, OGLPaints> impls =
  51         new HashMap<Integer, OGLPaints>(4, 1.0f);
  52 
  53     static {
  54         impls.put(SunGraphics2D.PAINT_GRADIENT, new Gradient());
  55         impls.put(SunGraphics2D.PAINT_LIN_GRADIENT, new LinearGradient());
  56         impls.put(SunGraphics2D.PAINT_RAD_GRADIENT, new RadialGradient());
  57         impls.put(SunGraphics2D.PAINT_TEXTURE, new Texture());
  58     }
  59 
  60     /**
  61      * Attempts to locate an implementation corresponding to the paint state
  62      * of the provided SunGraphics2D object.  If no implementation can be
  63      * found, or if the paint cannot be accelerated under the conditions
  64      * of the SunGraphics2D, this method returns false; otherwise, returns
  65      * true.
  66      */
  67     static boolean isValid(SunGraphics2D sg2d) {
  68         OGLPaints impl = impls.get(sg2d.paintState);
  69         return (impl != null && impl.isPaintValid(sg2d));
  70     }
  71 
  72     /**
  73      * Returns true if this implementation is able to accelerate the
  74      * Paint object associated with, and under the conditions of, the
  75      * provided SunGraphics2D instance; otherwise returns false.
  76      */
  77     abstract boolean isPaintValid(SunGraphics2D sg2d);
  78 
  79 /************************* GradientPaint support ****************************/
  80 
  81     private static class Gradient extends OGLPaints {
  82         private Gradient() {}
  83 
  84         /**
  85          * There are no restrictions for accelerating GradientPaint, so
  86          * this method always returns true.
  87          */
  88         @Override
  89         boolean isPaintValid(SunGraphics2D sg2d) {
  90             return true;
  91         }
  92     }
  93 
  94 /************************** TexturePaint support ****************************/
  95 
  96     private static class Texture extends OGLPaints {
  97         private Texture() {}
  98 
  99         /**
 100          * Returns true if the given TexturePaint instance can be used by the
 101          * accelerated OGLPaints.Texture implementation.  A TexturePaint is
 102          * considered valid if the following conditions are met:
 103          *   - the texture image dimensions are power-of-two (or the
 104          *     GL_ARB_texture_non_power_of_two extension is present)
 105          *   - the texture image can be (or is already) cached in an OpenGL
 106          *     texture object
 107          */
 108         @Override
 109         boolean isPaintValid(SunGraphics2D sg2d) {
 110             TexturePaint paint = (TexturePaint)sg2d.paint;
 111             OGLSurfaceData dstData = (OGLSurfaceData)sg2d.surfaceData;
 112             BufferedImage bi = paint.getImage();
 113 
 114             // see if texture-non-pow2 extension is available
 115             if (!dstData.isTexNonPow2Available()) {
 116                 int imgw = bi.getWidth();
 117                 int imgh = bi.getHeight();
 118 
 119                 // verify that the texture image dimensions are pow2
 120                 if ((imgw & (imgw - 1)) != 0 || (imgh & (imgh - 1)) != 0) {
 121                     return false;
 122                 }
 123             }
 124 
 125             SurfaceData srcData =
 126                 dstData.getSourceSurfaceData(bi,
 127                                              SunGraphics2D.TRANSFORM_ISIDENT,
 128                                              CompositeType.SrcOver, null);
 129             if (!(srcData instanceof OGLSurfaceData)) {
 130                 // REMIND: this is a hack that attempts to cache the system
 131                 //         memory image from the TexturePaint instance into an
 132                 //         OpenGL texture...
 133                 srcData =
 134                     dstData.getSourceSurfaceData(bi,
 135                                                  SunGraphics2D.TRANSFORM_ISIDENT,
 136                                                  CompositeType.SrcOver, null);
 137                 if (!(srcData instanceof OGLSurfaceData)) {
 138                     return false;
 139                 }
 140             }
 141 
 142             // verify that the source surface is actually a texture
 143             OGLSurfaceData oglData = (OGLSurfaceData)srcData;
 144             if (oglData.getType() != OGLSurfaceData.TEXTURE) {
 145                 return false;
 146             }
 147 
 148             return true;
 149         }
 150     }
 151 
 152 /****************** Shared MultipleGradientPaint support ********************/
 153 
 154     private static abstract class MultiGradient extends OGLPaints {
 155         protected MultiGradient() {}
 156 
 157         /**
 158          * Returns true if the given MultipleGradientPaint instance can be
 159          * used by the accelerated OGLPaints.MultiGradient implementation.
 160          * A MultipleGradientPaint is considered valid if the following
 161          * conditions are met:
 162          *   - the number of gradient "stops" is <= MAX_FRACTIONS
 163          *   - the destination has support for fragment shaders
 164          */
 165         @Override
 166         boolean isPaintValid(SunGraphics2D sg2d) {
 167             MultipleGradientPaint paint = (MultipleGradientPaint)sg2d.paint;
 168             // REMIND: ugh, this creates garbage; would be nicer if
 169             // we had a MultipleGradientPaint.getNumStops() method...
 170             if (paint.getFractions().length > MULTI_MAX_FRACTIONS) {
 171                 return false;
 172             }
 173 
 174             OGLSurfaceData dstData = (OGLSurfaceData)sg2d.surfaceData;
 175             OGLGraphicsConfig gc = dstData.getOGLGraphicsConfig();
 176             if (!gc.isCapPresent(CAPS_EXT_GRAD_SHADER)) {
 177                 return false;
 178             }
 179 
 180             return true;
 181         }
 182     }
 183 
 184 /********************** LinearGradientPaint support *************************/
 185 
 186     private static class LinearGradient extends MultiGradient {
 187         private LinearGradient() {}
 188 
 189         @Override
 190         boolean isPaintValid(SunGraphics2D sg2d) {
 191             LinearGradientPaint paint = (LinearGradientPaint)sg2d.paint;
 192 
 193             if (paint.getFractions().length == 2 &&
 194                 paint.getCycleMethod() != CycleMethod.REPEAT &&
 195                 paint.getColorSpace() != ColorSpaceType.LINEAR_RGB)
 196             {
 197                 // we can delegate to the optimized two-color gradient
 198                 // codepath, which does not require fragment shader support
 199                 return true;
 200             }
 201 
 202             return super.isPaintValid(sg2d);
 203         }
 204     }
 205 
 206 /********************** RadialGradientPaint support *************************/
 207 
 208     private static class RadialGradient extends MultiGradient {
 209         private RadialGradient() {}
 210     }
 211 }