1 /*
   2  * Copyright (c) 2010, 2016, 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.impl;
  27 
  28 import java.security.AccessController;
  29 import java.security.PrivilegedAction;
  30 import java.util.Arrays;
  31 import java.util.Collections;
  32 import java.util.List;
  33 import java.util.Properties;
  34 import java.util.StringTokenizer;
  35 import com.sun.javafx.PlatformUtil;
  36 import com.sun.javafx.util.Utils;
  37 
  38 /**
  39  * Contains the runtime arguments used by Prism.
  40  */
  41 public final class PrismSettings {
  42 
  43     public static final boolean verbose;
  44     public static final boolean debug;
  45     public static final boolean trace;
  46     public static final boolean printAllocs;
  47     public static final boolean isVsyncEnabled;
  48     public static final boolean dirtyOptsEnabled;
  49     public static final boolean occlusionCullingEnabled;
  50     public static final boolean scrollCacheOpt;
  51     public static final boolean threadCheck;
  52     public static final boolean cacheSimpleShapes;
  53     public static final boolean cacheComplexShapes;
  54     public static final boolean useNewImageLoader;
  55     public static final List<String> tryOrder;
  56     public static final int prismStatFrequency;
  57     public static final boolean doNativePisces;
  58     public static final boolean useMarlinRasterizer;
  59     public static final String refType;
  60     public static final boolean forceRepaint;
  61     public static final boolean noFallback;
  62     public static final boolean showDirtyRegions;
  63     public static final boolean showOverdraw;
  64     public static final boolean printRenderGraph;
  65     public static final int minRTTSize;
  66     public static final int dirtyRegionCount;
  67     public static final boolean disableBadDriverWarning;
  68     public static final boolean forceGPU;
  69     public static final int maxTextureSize;
  70     public static final int primTextureSize;
  71     public static final boolean disableRegionCaching;
  72     public static final boolean forcePow2;
  73     public static final boolean noClampToZero;
  74     public static final boolean disableD3D9Ex;
  75     public static final boolean allowHiDPIScaling;
  76     public static final long maxVram;
  77     public static final long targetVram;
  78     public static final boolean poolStats;
  79     public static final boolean poolDebug;
  80     public static final boolean disableEffects;
  81     public static final int glyphCacheWidth;
  82     public static final int glyphCacheHeight;
  83     public static final String perfLog;
  84     public static final boolean perfLogExitFlush;
  85     public static final boolean perfLogFirstPaintFlush;
  86     public static final boolean perfLogFirstPaintExit;
  87     public static final boolean superShader;
  88     public static final boolean forceUploadingPainter;
  89     public static final boolean forceAlphaTestShader;
  90     public static final boolean forceNonAntialiasedShape;
  91 
  92 
  93     private PrismSettings() {
  94     }
  95 
  96     private static void printBooleanOption(boolean opt, String trueStr) {
  97         if (opt) {
  98             System.out.println(trueStr);
  99         } else {
 100             System.out.print("Not ");
 101             System.out.print(Character.toLowerCase(trueStr.charAt(0)));
 102             System.out.println(trueStr.substring(1));
 103         }
 104     }
 105 
 106     static {
 107         final Properties systemProperties =
 108                 (Properties) AccessController.doPrivileged(
 109                         (PrivilegedAction) () -> System.getProperties());
 110 
 111         /* Vsync */
 112         isVsyncEnabled  = getBoolean(systemProperties, "prism.vsync", true)
 113                               && !getBoolean(systemProperties,
 114                                              "javafx.animation.fullspeed",
 115                                              false);
 116 
 117         /* Dirty region optimizations */
 118         dirtyOptsEnabled = getBoolean(systemProperties, "prism.dirtyopts",
 119                                       true);
 120         occlusionCullingEnabled =
 121                 dirtyOptsEnabled && getBoolean(systemProperties,
 122                                                "prism.occlusion.culling",
 123                                                true);
 124 
 125         // The maximum number of dirty regions to use. The absolute max that we can
 126         // support at present is 15.
 127         dirtyRegionCount = Utils.clamp(0, getInt(systemProperties, "prism.dirtyregioncount", 6, null), 15);
 128 
 129         // Scrolling cache optimization
 130         // Disabled as a workaround for RT-39755.
 131         scrollCacheOpt = getBoolean(systemProperties, "prism.scrollcacheopt", false);
 132 
 133         /* Dirty region optimizations */
 134         threadCheck = getBoolean(systemProperties, "prism.threadcheck", false);
 135 
 136         /* Draws overlay rectangles showing where the dirty regions were */
 137         showDirtyRegions = getBoolean(systemProperties, "prism.showdirty", false);
 138 
 139         /*
 140          * Draws overlay rectangles showing not only the dirty regions, but how many times
 141          * each area within that dirty region was drawn (covered by bounds of a drawn object).
 142          */
 143         showOverdraw = getBoolean(systemProperties, "prism.showoverdraw", false);
 144 
 145         /* Prints out the render graph, annotated with dirty opts information */
 146         printRenderGraph = getBoolean(systemProperties, "prism.printrendergraph", false);
 147 
 148         /* Force scene repaint on every frame */
 149         forceRepaint = getBoolean(systemProperties, "prism.forcerepaint", false);
 150 
 151         /* disable fallback to another toolkit if prism couldn't be init-ed */
 152         noFallback = getBoolean(systemProperties, "prism.noFallback", false);
 153 
 154         /* Shape caching optimizations */
 155         String cache = systemProperties.getProperty("prism.cacheshapes",
 156                                                     "complex");
 157         if ("all".equals(cache) || "true".equals(cache)) {
 158             cacheSimpleShapes = true;
 159             cacheComplexShapes = true;
 160         } else if ("complex".equals(cache)) {
 161             cacheSimpleShapes = false;
 162             cacheComplexShapes = true;
 163         } else {
 164             cacheSimpleShapes = false;
 165             cacheComplexShapes = false;
 166         }
 167 
 168         /* New javafx-iio image loader */
 169         useNewImageLoader = getBoolean(systemProperties, "prism.newiio", true);
 170 
 171         /* Verbose output*/
 172         verbose = getBoolean(systemProperties, "prism.verbose", false);
 173 
 174         /* Prism statistics print frequency, <=0 means "do not print" */
 175         prismStatFrequency =
 176                 getInt(systemProperties, "prism.printStats",
 177                        0, 1, "Try -Dprism.printStats=<true or number>");
 178 
 179         /* Debug output*/
 180         debug = getBoolean(systemProperties, "prism.debug", false);
 181 
 182         /* Trace output*/
 183         trace = getBoolean(systemProperties, "prism.trace", false);
 184 
 185         /* Print texture allocation data */
 186         printAllocs = getBoolean(systemProperties, "prism.printallocs", false);
 187 
 188         /* Disable bad driver check warning */
 189         disableBadDriverWarning = getBoolean(systemProperties,
 190                                              "prism.disableBadDriverWarning",
 191                                              false);
 192 
 193         /* Force GPU, if GPU is PS 3 capable, disable GPU qualification check. */
 194         forceGPU = getBoolean(systemProperties, "prism.forceGPU", false);
 195 
 196         String order = systemProperties.getProperty("prism.order");
 197         String[] tryOrderArr;
 198         if (order != null) {
 199             tryOrderArr = split(order, ",");
 200         } else {
 201             if (PlatformUtil.isWindows()) {
 202                 tryOrderArr = new String[] { "d3d", "sw" };
 203             } else if (PlatformUtil.isMac()) {
 204                 tryOrderArr = new String[] { "es2", "sw" };
 205             } else if (PlatformUtil.isIOS()) {
 206                 tryOrderArr = new String[] { "es2" };
 207             } else if (PlatformUtil.isAndroid()) {
 208                     tryOrderArr = new String[] { "es2" };
 209             } else if (PlatformUtil.isLinux()) {
 210                 tryOrderArr = new String[] { "es2", "sw" };
 211             } else {
 212                 tryOrderArr = new String[] { "sw" };
 213             }
 214         }
 215 
 216         tryOrder = Collections.unmodifiableList(Arrays.asList(tryOrderArr));
 217 
 218         useMarlinRasterizer = getBoolean(systemProperties, "prism.marlinrasterizer", false);
 219         if (useMarlinRasterizer) {
 220             doNativePisces = false;
 221         } else {
 222             String npprop = systemProperties.getProperty("prism.nativepisces");
 223             if (npprop == null) {
 224                 doNativePisces = PlatformUtil.isEmbedded() || !PlatformUtil.isLinux();
 225             } else {
 226                 doNativePisces = Boolean.parseBoolean(npprop);
 227             }
 228         }
 229 
 230         String primtex = systemProperties.getProperty("prism.primtextures");
 231         if (primtex == null) {
 232             primTextureSize = PlatformUtil.isEmbedded() ? -1 : 0;
 233         } else if (primtex.equals("true")) {
 234             primTextureSize = -1;
 235         } else if (primtex.equals("false")) {
 236             primTextureSize = 0;
 237         } else {
 238             primTextureSize =
 239                     parseInt(primtex, 0,
 240                              "Try -Dprism.primtextures=[true|false|<number>]");
 241         }
 242 
 243         /* Setting for reference type used by Disposer */
 244         refType = systemProperties.getProperty("prism.reftype");
 245 
 246         forcePow2 = getBoolean(systemProperties, "prism.forcepowerof2", false);
 247         noClampToZero = getBoolean(systemProperties, "prism.noclamptozero", false);
 248 
 249         allowHiDPIScaling = getBoolean(systemProperties, "prism.allowhidpi", true);
 250 
 251         maxVram = getLong(systemProperties, "prism.maxvram", 512 * 1024 * 1024,
 252                           "Try -Dprism.maxvram=<long>[kKmMgG]");
 253         targetVram = getLong(systemProperties, "prism.targetvram", maxVram / 8, maxVram,
 254                              "Try -Dprism.targetvram=<long>[kKmMgG]|<double(0,100)>%");
 255         poolStats = getBoolean(systemProperties, "prism.poolstats", false);
 256         poolDebug = getBoolean(systemProperties, "prism.pooldebug", false);
 257 
 258         if (verbose) {
 259             System.out.print("Prism pipeline init order: ");
 260             for (String s : tryOrder) {
 261                 System.out.print(s+" ");
 262             }
 263             System.out.println("");
 264             if (useMarlinRasterizer) {
 265                 System.out.println("Using Marlin rasterizer");
 266             } else {
 267                 String piscestype = (doNativePisces ? "native" : "java");
 268                 System.out.println("Using " + piscestype + "-based Pisces rasterizer");
 269             }
 270             printBooleanOption(dirtyOptsEnabled, "Using dirty region optimizations");
 271             if (primTextureSize == 0) {
 272                 System.out.println("Not using texture mask for primitives");
 273             } else if (primTextureSize < 0) {
 274                 System.out.println("Using system sized mask for primitives");
 275             } else {
 276                 System.out.println("Using "+primTextureSize+" sized mask for primitives");
 277             }
 278             printBooleanOption(forcePow2, "Forcing power of 2 sizes for textures");
 279             printBooleanOption(!noClampToZero, "Using hardware CLAMP_TO_ZERO mode");
 280             printBooleanOption(allowHiDPIScaling, "Opting in for HiDPI pixel scaling");
 281         }
 282 
 283         /*
 284          * Setting for maximum texture size. Default is 4096.
 285          * This will clamp the limit reported by the card to the specified
 286          * value. A value of <= 0 will disable this clamping, causing the
 287          * limit reported by the card to be used without modification.
 288          *
 289          * See RT-21998. This is a workaround for the fact that we don't
 290          * yet handle the case where a texture allocation fails during
 291          * rendering of a very large tiled image.
 292          */
 293         int size = getInt(systemProperties, "prism.maxTextureSize",
 294                           4096, "Try -Dprism.maxTextureSize=<number>");
 295 
 296         if (size <= 0) {
 297             size = Integer.MAX_VALUE;
 298         }
 299         maxTextureSize = size;
 300 
 301         /*
 302          * Check minimum RTT size
 303          * This is needed for some embedded platforms to avoid rendering artifacts
 304          * when rendering into small RTT.
 305          */
 306        minRTTSize = getInt(systemProperties, "prism.minrttsize",
 307                PlatformUtil.isEmbedded() ? 16 : 0, "Try -Dprism.minrttsize=<number>");
 308 
 309         disableRegionCaching = getBoolean(systemProperties,
 310                                           "prism.disableRegionCaching",
 311                                           false);
 312 
 313         disableD3D9Ex = getBoolean(systemProperties, "prism.disableD3D9Ex", false);
 314 
 315         disableEffects = getBoolean(systemProperties, "prism.disableEffects", false);
 316 
 317         glyphCacheWidth = getInt(systemProperties, "prism.glyphCacheWidth", 1024,
 318                 "Try -Dprism.glyphCacheWidth=<number>");
 319         glyphCacheHeight = getInt(systemProperties, "prism.glyphCacheHeight", 1024,
 320                 "Try -Dprism.glyphCacheHeight=<number>");
 321 
 322         /*
 323          * Performance Logger flags
 324          * Enable the performance logger, print on exit, print on first paint etc.
 325          */
 326         perfLog = systemProperties.getProperty("sun.perflog");
 327         perfLogExitFlush = getBoolean(systemProperties, "sun.perflog.fx.exitflush", false, true);
 328         perfLogFirstPaintFlush = getBoolean(systemProperties, "sun.perflog.fx.firstpaintflush", false, true);
 329         perfLogFirstPaintExit = getBoolean(systemProperties, "sun.perflog.fx.firstpaintexit", false, true);
 330 
 331         superShader = getBoolean(systemProperties, "prism.supershader", true);
 332 
 333         // Force uploading painter (e.g., to avoid Linux live-resize jittering)
 334         forceUploadingPainter = getBoolean(systemProperties, "prism.forceUploadingPainter", false);
 335 
 336         // Force the use of fragment shader that does alpha testing (i.e. discard if alpha == 0.0)
 337         forceAlphaTestShader = getBoolean(systemProperties, "prism.forceAlphaTestShader", false);
 338 
 339         // Force non anti-aliasing (not smooth) shape rendering
 340         forceNonAntialiasedShape = getBoolean(systemProperties, "prism.forceNonAntialiasedShape", false);
 341 
 342     }
 343 
 344     private static int parseInt(String s, int dflt, int trueDflt,
 345                                 String errMsg) {
 346         return "true".equalsIgnoreCase(s)
 347                    ? trueDflt
 348                    : parseInt(s, dflt, errMsg);
 349     }
 350 
 351     private static int parseInt(String s, int dflt, String errMsg) {
 352         if (s != null) {
 353             try {
 354                 return Integer.parseInt(s);
 355             } catch (Exception e) {
 356                 if (errMsg != null) {
 357                     System.err.println(errMsg);
 358                 }
 359             }
 360         }
 361 
 362         return dflt;
 363     }
 364 
 365     private static long parseLong(String s, long dflt, long rel, String errMsg) {
 366         if (s != null && s.length() > 0) {
 367             long mult = 1;
 368             if (s.endsWith("%")) {
 369                 if (rel > 0) {
 370                     try {
 371                         s = s.substring(0, s.length() - 1);
 372                         double percent = Double.parseDouble(s);
 373                         if (percent >= 0 && percent <= 100) {
 374                             return Math.round(rel * percent / 100.0);
 375                         }
 376                     } catch (Exception e) {
 377                     }
 378                 }
 379 
 380                 if (errMsg != null) {
 381                     System.err.println(errMsg);
 382                 }
 383                 return dflt;
 384             }
 385             if (s.endsWith("k") || s.endsWith("K")) {
 386                 mult = 1024L;
 387             } else if (s.endsWith("m") || s.endsWith("M")) {
 388                 mult = 1024L * 1024L;
 389             } else if (s.endsWith("g") || s.endsWith("G")) {
 390                 mult = 1024L * 1024L * 1024L;
 391             }
 392             if (mult > 1) {
 393                 s = s.substring(0, s.length() - 1);
 394             }
 395             try {
 396                 return Long.parseLong(s) * mult;
 397             } catch (Exception e) {
 398                 if (errMsg != null) {
 399                     System.err.println(errMsg);
 400                 }
 401             }
 402         }
 403 
 404         return dflt;
 405     }
 406 
 407     /* A simple version of String.split(), since that isn't available on CDC */
 408     private static String[] split(String str, String delim) {
 409         StringTokenizer st = new StringTokenizer(str, delim);
 410         String[] ret = new String[st.countTokens()];
 411         int i = 0;
 412         while (st.hasMoreTokens()) {
 413             ret[i++] = st.nextToken();
 414         }
 415         return ret;
 416     }
 417 
 418     private static boolean getBoolean(Properties properties,
 419                                       String key,
 420                                       boolean dflt) {
 421         final String strval = properties.getProperty(key);
 422         return (strval != null) ? Boolean.parseBoolean(strval) : dflt;
 423     }
 424 
 425     private static boolean getBoolean(Properties properties,
 426                                       String key,
 427                                       boolean dflt,
 428                                       boolean dfltIfDefined) {
 429         final String strval = properties.getProperty(key);
 430         if (strval != null && strval.length() == 0) return dfltIfDefined;
 431         return (strval != null) ? Boolean.parseBoolean(strval) : dflt;
 432     }
 433 
 434     private static int getInt(Properties properties,
 435                               String key,
 436                               int dflt,
 437                               int trueDflt,
 438                               String errMsg) {
 439         return parseInt(properties.getProperty(key),
 440                         dflt,
 441                         trueDflt,
 442                         errMsg);
 443     }
 444 
 445     private static int getInt(Properties properties,
 446                               String key,
 447                               int dflt,
 448                               String errMsg) {
 449         return parseInt(properties.getProperty(key),
 450                         dflt,
 451                         errMsg);
 452     }
 453 
 454     private static long getLong(Properties properties,
 455                                 String key,
 456                                 long dflt,
 457                                 String errMsg)
 458     {
 459         return parseLong(properties.getProperty(key),
 460                          dflt, 0,
 461                          errMsg);
 462     }
 463 
 464     private static long getLong(Properties properties,
 465                                 String key,
 466                                 long dflt, long rel,
 467                                 String errMsg)
 468     {
 469         return parseLong(properties.getProperty(key),
 470                          dflt, rel,
 471                          errMsg);
 472     }
 473 }