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 }