1 /* 2 * Copyright (c) 2009, 2015, 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 com.sun.prism.es2; 27 28 import java.io.InputStream; 29 import java.util.Map; 30 31 import com.sun.glass.ui.Screen; 32 import com.sun.javafx.PlatformUtil; 33 import com.sun.prism.Image; 34 import com.sun.prism.MediaFrame; 35 import com.sun.prism.Mesh; 36 import com.sun.prism.MeshView; 37 import com.sun.prism.PhongMaterial; 38 import com.sun.prism.PixelFormat; 39 import com.sun.prism.Presentable; 40 import com.sun.prism.PresentableState; 41 import com.sun.prism.RTTexture; 42 import com.sun.prism.Texture; 43 import com.sun.prism.Texture.Usage; 44 import com.sun.prism.Texture.WrapMode; 45 import com.sun.prism.impl.PrismSettings; 46 import com.sun.prism.impl.TextureResourcePool; 47 import com.sun.prism.impl.VertexBuffer; 48 import com.sun.prism.impl.ps.BaseShaderFactory; 49 import com.sun.prism.ps.Shader; 50 import com.sun.prism.ps.ShaderFactory; 51 import java.lang.reflect.Method; 52 import java.util.HashMap; 53 import java.util.WeakHashMap; 54 55 public class ES2ResourceFactory extends BaseShaderFactory { 56 private static final Map<Image,Texture> clampTexCache = new WeakHashMap<>(); 57 private static final Map<Image,Texture> repeatTexCache = new WeakHashMap<>(); 58 private static final Map<Image,Texture> mipmapTexCache = new WeakHashMap<>(); 59 60 private ES2Context context; 61 // Maximum size of the texture 62 private final int maxTextureSize; 63 64 ES2ResourceFactory(Screen screen) { 65 super(clampTexCache, repeatTexCache, mipmapTexCache); 66 context = new ES2Context(screen, this); 67 maxTextureSize = computeMaxTextureSize(); 68 69 if (PrismSettings.verbose) { 70 System.out.println("Non power of two texture support = " 71 + context.getGLContext().canCreateNonPowTwoTextures()); 72 System.out.println("Maximum number of vertex attributes = " 73 + context.getGLContext().getIntParam(GLContext.GL_MAX_VERTEX_ATTRIBS)); 74 int maxVUC, maxFUC, maxVC; 75 // We need this if-else block is because iMX6 doesn't support component queries 76 // and Mac doesn't support vectors queries. 77 if (PlatformUtil.isEmbedded()) { 78 // Multiply by 4 as it is documented that a vector has 4 components. 79 maxVUC = context.getGLContext().getIntParam(GLContext.GL_MAX_VERTEX_UNIFORM_VECTORS) * 4; 80 maxFUC = context.getGLContext().getIntParam(GLContext.GL_MAX_FRAGMENT_UNIFORM_VECTORS) * 4; 81 maxVC = context.getGLContext().getIntParam(GLContext.GL_MAX_VARYING_VECTORS) * 4; 82 } else { 83 maxVUC = context.getGLContext().getIntParam(GLContext.GL_MAX_VERTEX_UNIFORM_COMPONENTS); 84 maxFUC = context.getGLContext().getIntParam(GLContext.GL_MAX_FRAGMENT_UNIFORM_COMPONENTS); 85 maxVC = context.getGLContext().getIntParam(GLContext.GL_MAX_VARYING_COMPONENTS); 86 } 87 System.out.println("Maximum number of uniform vertex components = " + maxVUC); 88 System.out.println("Maximum number of uniform fragment components = " + maxFUC); 89 System.out.println("Maximum number of varying components = " + maxVC); 90 System.out.println("Maximum number of texture units usable in a vertex shader = " 91 + context.getGLContext().getIntParam(GLContext.GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS)); 92 System.out.println("Maximum number of texture units usable in a fragment shader = " 93 + context.getGLContext().getIntParam(GLContext.GL_MAX_TEXTURE_IMAGE_UNITS)); 94 } 95 } 96 97 public TextureResourcePool getTextureResourcePool() { 98 return ES2VramPool.instance; 99 } 100 101 public Presentable createPresentable(PresentableState pState) { 102 return new ES2SwapChain(context, pState); 103 } 104 105 @Override 106 public boolean isCompatibleTexture(Texture tex) { 107 return tex instanceof ES2Texture; 108 } 109 110 @Override 111 protected boolean canClampToZero() { 112 return context.getGLContext().canClampToZero(); 113 } 114 115 @Override 116 protected boolean canRepeat() { 117 // Actually, this depends on the size. It works for pow2 textures... 118 return context.getGLContext().canCreateNonPowTwoTextures(); 119 } 120 121 @Override 122 protected boolean canClampToEdge() { 123 // Actually, this depends on the size. It works for pow2 textures... 124 return context.getGLContext().canCreateNonPowTwoTextures(); 125 } 126 127 public Texture createTexture(PixelFormat formatHint, 128 Usage usageHint, 129 WrapMode wrapMode, 130 int w, int h) 131 { 132 return createTexture(formatHint, usageHint, wrapMode, w, h, false); 133 } 134 135 @Override 136 public Texture createTexture(PixelFormat formatHint, Usage usageHint, 137 WrapMode wrapMode, int w, int h, boolean useMipmap) { 138 return ES2Texture.create(context, formatHint, wrapMode, w, h, useMipmap); 139 } 140 141 public Texture createTexture(MediaFrame frame) { 142 return ES2Texture.create(context, frame); 143 } 144 145 public int getRTTWidth(int w, WrapMode wrapMode) { 146 return ES2RTTexture.getCompatibleDimension(context, w, wrapMode); 147 } 148 149 public int getRTTHeight(int h, WrapMode wrapMode) { 150 return ES2RTTexture.getCompatibleDimension(context, h, wrapMode); 151 } 152 153 public RTTexture createRTTexture(int width, int height, WrapMode wrapMode) { 154 return createRTTexture(width, height, wrapMode, false); 155 } 156 157 public RTTexture createRTTexture(int width, int height, WrapMode wrapMode, boolean msaa) { 158 return ES2RTTexture.create(context, width, height, wrapMode, msaa); 159 } 160 161 public boolean isFormatSupported(PixelFormat format) { 162 GLFactory glFactory = ES2Pipeline.glFactory; 163 switch (format) { 164 case BYTE_RGB: 165 case BYTE_GRAY: 166 case BYTE_ALPHA: 167 case MULTI_YCbCr_420: 168 return true; 169 case BYTE_BGRA_PRE: 170 case INT_ARGB_PRE: 171 if (glFactory.isGL2() || PlatformUtil.isIOS()) { 172 return true; 173 } else { 174 // for OpenGLES, BGRA can be supported by extension - if 175 // we have it, use it 176 return glFactory.isGLExtensionSupported("GL_EXT_texture_format_BGRA8888"); 177 } 178 case FLOAT_XYZW: 179 return glFactory.isGL2() 180 // Unfortunately our support for float textures on GLES 181 // seems to be broken so we will defer use of this extension 182 // until we fix RT-26286. 183 // || glFactory.isGLExtensionSupported("GL_OES_texture_float") 184 ; 185 case BYTE_APPLE_422: 186 return glFactory.isGLExtensionSupported("GL_APPLE_ycbcr_422"); 187 default: 188 return false; 189 } 190 } 191 192 private int computeMaxTextureSize() { 193 int size = context.getGLContext().getMaxTextureSize(); 194 if (PrismSettings.verbose) { 195 System.out.println("Maximum supported texture size: " + size); 196 } 197 if (size > PrismSettings.maxTextureSize) { 198 size = PrismSettings.maxTextureSize; 199 if (PrismSettings.verbose) { 200 System.out.println("Maximum texture size clamped to " + size); 201 } 202 } 203 return size; 204 } 205 206 public int getMaximumTextureSize() { 207 return maxTextureSize; 208 } 209 210 public Shader createShader(InputStream pixelShaderCode, 211 Map<String, Integer> samplers, 212 Map<String, Integer> params, 213 int maxTexCoordIndex, 214 boolean isPixcoordUsed, 215 boolean isPerVertexColorUsed) { 216 // figure out the appropriate vertex shader and minimal set of 217 // vertex attributes to enable based on the given parameters 218 Map<String, Integer> attributes = 219 getVertexAttributes(isPerVertexColorUsed, maxTexCoordIndex); 220 221 // create the combined shader program 222 ES2Shader shader; 223 String vertexShaderCode = 224 createVertexShaderCode(isPerVertexColorUsed, maxTexCoordIndex); 225 shader = ES2Shader.createFromSource(context, vertexShaderCode, 226 pixelShaderCode, samplers, attributes, 227 maxTexCoordIndex, isPixcoordUsed); 228 229 return shader; 230 } 231 232 private static String createVertexShaderCode(boolean includePerVertexColor, 233 int maxTexCoordIndex) { 234 StringBuilder vsAttr = new StringBuilder(); 235 StringBuilder vsVary = new StringBuilder(); 236 StringBuilder vsMain = new StringBuilder(); 237 vsMain.append("void main() {\n"); 238 239 boolean includePosition = true; 240 if (includePosition) { 241 vsAttr.append("attribute vec2 positionAttr;\n"); 242 vsMain.append(" vec4 tmp = vec4(positionAttr, 0, 1);\n"); 243 vsMain.append(" gl_Position = mvpMatrix * tmp;\n"); 244 } 245 if (includePerVertexColor) { 246 vsAttr.append("attribute vec4 colorAttr;\n"); 247 vsVary.append("varying lowp vec4 perVertexColor;\n"); 248 vsMain.append(" perVertexColor = colorAttr;\n"); 249 } 250 if (maxTexCoordIndex >= 0) { 251 vsAttr.append("attribute vec2 texCoord0Attr;\n"); 252 vsVary.append("varying vec2 texCoord0;\n"); 253 vsMain.append(" texCoord0 = texCoord0Attr;\n"); 254 } 255 if (maxTexCoordIndex >= 1) { 256 vsAttr.append("attribute vec2 texCoord1Attr;\n"); 257 vsVary.append("varying vec2 texCoord1;\n"); 258 vsMain.append(" texCoord1 = texCoord1Attr;\n"); 259 } 260 261 vsMain.append("}\n"); 262 StringBuilder vs = new StringBuilder(); 263 264 vs.append("#ifdef GL_ES\n"); 265 vs.append("#else\n"); 266 vs.append("#define lowp\n"); 267 vs.append("#endif\n"); 268 vs.append("uniform mat4 mvpMatrix;\n"); 269 vs.append(vsAttr); 270 vs.append(vsVary); 271 vs.append(vsMain); 272 273 return vs.toString(); 274 } 275 276 private Map<String, Integer> getVertexAttributes(boolean includePerVertexColor, 277 int maxTexCoordIndex) { 278 Map<String, Integer> attributes = new HashMap<String, Integer>(); 279 280 boolean includePosition = true; 281 if (includePosition) { 282 attributes.put("positionAttr", 0); 283 } 284 if (includePerVertexColor) { 285 attributes.put("colorAttr", 1); 286 } 287 if (maxTexCoordIndex >= 0) { 288 attributes.put("texCoord0Attr", 2); 289 } 290 if (maxTexCoordIndex >= 1) { 291 attributes.put("texCoord1Attr", 3); 292 } 293 294 return attributes; 295 } 296 297 public Shader createStockShader(String name) { 298 if (name == null) { 299 throw new IllegalArgumentException("Shader name must be non-null"); 300 } 301 try { 302 InputStream stream = 303 ES2ResourceFactory.class.getResourceAsStream( 304 "glsl/" + name + ".frag"); 305 Class klass = 306 Class.forName("com.sun.prism.shader." + name + "_Loader"); 307 if (PrismSettings.verbose) { 308 System.out.println("ES2ResourceFactory: Prism - createStockShader: " + name + ".frag"); 309 } 310 Method m = 311 klass.getMethod("loadShader", new Class[]{ShaderFactory.class, 312 InputStream.class}); 313 return (Shader) m.invoke(null, new Object[]{this, stream}); 314 } catch (Throwable e) { 315 e.printStackTrace(); 316 throw new InternalError("Error loading stock shader " + name); 317 } 318 } 319 320 public VertexBuffer createVertexBuffer(int maxQuads) { 321 return new VertexBuffer(maxQuads); 322 } 323 324 public void dispose() { 325 context.clearContext(); 326 } 327 328 public PhongMaterial createPhongMaterial() { 329 return ES2PhongMaterial.create(context); 330 } 331 332 public MeshView createMeshView(Mesh mesh) { 333 return ES2MeshView.create(context, (ES2Mesh) mesh); 334 } 335 336 public Mesh createMesh() { 337 return ES2Mesh.create(context); 338 } 339 }