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 }