1 /* 2 * Copyright (c) 2019, 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 package sun.java2d.metal; 26 27 import sun.java2d.SunGraphics2D; 28 import sun.java2d.SurfaceData; 29 import sun.java2d.loops.CompositeType; 30 31 import java.awt.*; 32 import java.awt.MultipleGradientPaint.ColorSpaceType; 33 import java.awt.MultipleGradientPaint.CycleMethod; 34 import java.awt.image.BufferedImage; 35 import java.util.HashMap; 36 import java.util.Map; 37 38 import static sun.java2d.metal.MTLContext.MTLContextCaps.CAPS_EXT_GRAD_SHADER; 39 import static sun.java2d.pipe.BufferedPaints.MULTI_MAX_FRACTIONS; 40 41 abstract class MTLPaints { 42 43 /** 44 * Holds all registered implementations, using the corresponding 45 * SunGraphics2D.PAINT_* constant as the hash key. 46 */ 47 private static Map<Integer, MTLPaints> impls = 48 new HashMap<Integer, MTLPaints>(4, 1.0f); 49 50 static { 51 impls.put(SunGraphics2D.PAINT_GRADIENT, new Gradient()); 52 impls.put(SunGraphics2D.PAINT_LIN_GRADIENT, new LinearGradient()); 53 impls.put(SunGraphics2D.PAINT_RAD_GRADIENT, new RadialGradient()); 54 impls.put(SunGraphics2D.PAINT_TEXTURE, new Texture()); 55 } 56 57 /** 58 * Attempts to locate an implementation corresponding to the paint state 59 * of the provided SunGraphics2D object. If no implementation can be 60 * found, or if the paint cannot be accelerated under the conditions 61 * of the SunGraphics2D, this method returns false; otherwise, returns 62 * true. 63 */ 64 static boolean isValid(SunGraphics2D sg2d) { 65 MTLPaints impl = impls.get(sg2d.paintState); 66 return (impl != null && impl.isPaintValid(sg2d)); 67 } 68 69 /** 70 * Returns true if this implementation is able to accelerate the 71 * Paint object associated with, and under the conditions of, the 72 * provided SunGraphics2D instance; otherwise returns false. 73 */ 74 abstract boolean isPaintValid(SunGraphics2D sg2d); 75 76 /************************* GradientPaint support ****************************/ 77 78 private static class Gradient extends MTLPaints { 79 private Gradient() {} 80 81 /** 82 * There are no restrictions for accelerating GradientPaint, so 83 * this method always returns true. 84 */ 85 @Override 86 boolean isPaintValid(SunGraphics2D sg2d) { 87 return true; 88 } 89 } 90 91 /************************** TexturePaint support ****************************/ 92 93 private static class Texture extends MTLPaints { 94 private Texture() {} 95 96 /** 97 * Returns true if the given TexturePaint instance can be used by the 98 * accelerated MTLPaints.Texture implementation. A TexturePaint is 99 * considered valid if the following conditions are met: 100 * - the texture image dimensions are power-of-two (or the 101 * GL_ARB_texture_non_power_of_two extension is present) 102 * - the texture image can be (or is already) cached in an OpenGL 103 * texture object 104 */ 105 @Override 106 boolean isPaintValid(SunGraphics2D sg2d) { 107 TexturePaint paint = (TexturePaint)sg2d.paint; 108 MTLSurfaceData dstData = (MTLSurfaceData)sg2d.surfaceData; 109 BufferedImage bi = paint.getImage(); 110 111 // see if texture-non-pow2 extension is available 112 if (!dstData.isTexNonPow2Available()) { 113 int imgw = bi.getWidth(); 114 int imgh = bi.getHeight(); 115 116 // verify that the texture image dimensions are pow2 117 if ((imgw & (imgw - 1)) != 0 || (imgh & (imgh - 1)) != 0) { 118 return false; 119 } 120 } 121 122 SurfaceData srcData = 123 dstData.getSourceSurfaceData(bi, 124 SunGraphics2D.TRANSFORM_ISIDENT, 125 CompositeType.SrcOver, null); 126 if (!(srcData instanceof MTLSurfaceData)) { 127 // REMIND: this is a hack that attempts to cache the system 128 // memory image from the TexturePaint instance into an 129 // OpenGL texture... 130 srcData = 131 dstData.getSourceSurfaceData(bi, 132 SunGraphics2D.TRANSFORM_ISIDENT, 133 CompositeType.SrcOver, null); 134 if (!(srcData instanceof MTLSurfaceData)) { 135 return false; 136 } 137 } 138 139 // verify that the source surface is actually a texture 140 MTLSurfaceData oglData = (MTLSurfaceData)srcData; 141 if (oglData.getType() != MTLSurfaceData.TEXTURE) { 142 return false; 143 } 144 145 return true; 146 } 147 } 148 149 /****************** Shared MultipleGradientPaint support ********************/ 150 151 private abstract static class MultiGradient extends MTLPaints { 152 protected MultiGradient() {} 153 154 /** 155 * Returns true if the given MultipleGradientPaint instance can be 156 * used by the accelerated MTLPaints.MultiGradient implementation. 157 * A MultipleGradientPaint is considered valid if the following 158 * conditions are met: 159 * - the number of gradient "stops" is <= MAX_FRACTIONS 160 * - the destination has support for fragment shaders 161 */ 162 @Override 163 boolean isPaintValid(SunGraphics2D sg2d) { 164 MultipleGradientPaint paint = (MultipleGradientPaint)sg2d.paint; 165 // REMIND: ugh, this creates garbage; would be nicer if 166 // we had a MultipleGradientPaint.getNumStops() method... 167 if (paint.getFractions().length > MULTI_MAX_FRACTIONS) { 168 return false; 169 } 170 171 MTLSurfaceData dstData = (MTLSurfaceData)sg2d.surfaceData; 172 MTLGraphicsConfig gc = dstData.getMTLGraphicsConfig(); 173 if (!gc.isCapPresent(CAPS_EXT_GRAD_SHADER)) { 174 return false; 175 } 176 177 return true; 178 } 179 } 180 181 /********************** LinearGradientPaint support *************************/ 182 183 private static class LinearGradient extends MultiGradient { 184 private LinearGradient() {} 185 186 @Override 187 boolean isPaintValid(SunGraphics2D sg2d) { 188 LinearGradientPaint paint = (LinearGradientPaint)sg2d.paint; 189 190 if (paint.getFractions().length == 2 && 191 paint.getCycleMethod() != CycleMethod.REPEAT && 192 paint.getColorSpace() != ColorSpaceType.LINEAR_RGB) 193 { 194 // we can delegate to the optimized two-color gradient 195 // codepath, which does not require fragment shader support 196 return true; 197 } 198 199 return super.isPaintValid(sg2d); 200 } 201 } 202 203 /********************** RadialGradientPaint support *************************/ 204 205 private static class RadialGradient extends MultiGradient { 206 private RadialGradient() {} 207 } 208 }