1 /*
   2  * Copyright (c) 2007, 2018, 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.marlin;
  27 
  28 import java.security.AccessController;
  29 import static com.sun.marlin.MarlinUtils.logInfo;
  30 import com.sun.util.reentrant.ReentrantContextProvider;
  31 import com.sun.util.reentrant.ReentrantContextProviderCLQ;
  32 import com.sun.util.reentrant.ReentrantContextProviderTL;
  33 import com.sun.javafx.geom.PathIterator;
  34 import com.sun.prism.BasicStroke;
  35 import java.security.PrivilegedAction;
  36 
  37 /**
  38  * Marlin RendererEngine implementation (derived from Pisces)
  39  */
  40 public final class MarlinRenderingEngine implements MarlinConst
  41 {
  42     /**
  43      * Private constructor to prevent instantiation.
  44      */
  45     private MarlinRenderingEngine() {
  46     }
  47 
  48     static {
  49         if (PathIterator.WIND_NON_ZERO != WIND_NON_ZERO ||
  50             PathIterator.WIND_EVEN_ODD != WIND_EVEN_ODD ||
  51             BasicStroke.JOIN_MITER != JOIN_MITER ||
  52             BasicStroke.JOIN_ROUND != JOIN_ROUND ||
  53             BasicStroke.JOIN_BEVEL != JOIN_BEVEL ||
  54             BasicStroke.CAP_BUTT != CAP_BUTT ||
  55             BasicStroke.CAP_ROUND != CAP_ROUND ||
  56             BasicStroke.CAP_SQUARE != CAP_SQUARE)
  57         {
  58             throw new InternalError("mismatched renderer constants");
  59         }
  60     }
  61 
  62     // --- RendererContext handling ---
  63     // use ThreadLocal or ConcurrentLinkedQueue to get one RendererContext
  64     private static final boolean USE_THREAD_LOCAL;
  65 
  66     // reference type stored in either TL or CLQ
  67     static final int REF_TYPE;
  68 
  69     // Per-thread RendererContext
  70     private static final ReentrantContextProvider<RendererContext> RDR_CTX_PROVIDER;
  71 
  72     // Static initializer to use TL or CLQ mode
  73     static {
  74         USE_THREAD_LOCAL = MarlinProperties.isUseThreadLocal();
  75 
  76         // Soft reference by default:
  77         final String refType = AccessController.doPrivileged(
  78             (PrivilegedAction<String>) () -> {
  79                 String value = System.getProperty("prism.marlin.useRef");
  80                 return (value == null) ? "soft" : value;
  81             });
  82         switch (refType) {
  83             default:
  84             case "soft":
  85                 REF_TYPE = ReentrantContextProvider.REF_SOFT;
  86                 break;
  87             case "weak":
  88                 REF_TYPE = ReentrantContextProvider.REF_WEAK;
  89                 break;
  90             case "hard":
  91                 REF_TYPE = ReentrantContextProvider.REF_HARD;
  92                 break;
  93         }
  94 
  95         if (USE_THREAD_LOCAL) {
  96             RDR_CTX_PROVIDER = new ReentrantContextProviderTL<RendererContext>(REF_TYPE)
  97                 {
  98                     @Override
  99                     protected RendererContext newContext() {
 100                         return RendererContext.createContext();
 101                     }
 102                 };
 103         } else {
 104             RDR_CTX_PROVIDER = new ReentrantContextProviderCLQ<RendererContext>(REF_TYPE)
 105                 {
 106                     @Override
 107                     protected RendererContext newContext() {
 108                         return RendererContext.createContext();
 109                     }
 110                 };
 111         }
 112 
 113         logSettings(Renderer.class.getName());
 114     }
 115 
 116     private static boolean SETTINGS_LOGGED = !ENABLE_LOGS;
 117 
 118     public static void logSettings(final String reClass) {
 119         // log information at startup
 120         if (SETTINGS_LOGGED) {
 121             return;
 122         }
 123         SETTINGS_LOGGED = true;
 124 
 125         String refType;
 126         switch (REF_TYPE) {
 127             default:
 128             case ReentrantContextProvider.REF_HARD:
 129                 refType = "hard";
 130                 break;
 131             case ReentrantContextProvider.REF_SOFT:
 132                 refType = "soft";
 133                 break;
 134             case ReentrantContextProvider.REF_WEAK:
 135                 refType = "weak";
 136                 break;
 137         }
 138 
 139         logInfo("=========================================================="
 140                 + "=====================");
 141 
 142         logInfo("Marlin software rasterizer    = ENABLED");
 143         logInfo("Version                       = ["
 144                 + Version.getVersion() + "]");
 145         logInfo("prism.marlin                  = "
 146                 + reClass);
 147         logInfo("prism.marlin.useThreadLocal   = "
 148                 + USE_THREAD_LOCAL);
 149         logInfo("prism.marlin.useRef           = "
 150                 + refType);
 151 
 152         logInfo("prism.marlin.edges            = "
 153                 + MarlinConst.INITIAL_EDGES_COUNT);
 154         logInfo("prism.marlin.pixelWidth       = "
 155                 + MarlinConst.INITIAL_PIXEL_WIDTH);
 156         logInfo("prism.marlin.pixelHeight      = "
 157                 + MarlinConst.INITIAL_PIXEL_HEIGHT);
 158 
 159         logInfo("prism.marlin.profile          = "
 160                 + (MarlinProperties.isProfileQuality() ?
 161                     "quality" : "speed"));
 162 
 163         logInfo("prism.marlin.subPixel_log2_X  = "
 164                 + MarlinConst.SUBPIXEL_LG_POSITIONS_X);
 165         logInfo("prism.marlin.subPixel_log2_Y  = "
 166                 + MarlinConst.SUBPIXEL_LG_POSITIONS_Y);
 167 
 168         logInfo("prism.marlin.blockSize_log2   = "
 169                 + MarlinConst.BLOCK_SIZE_LG);
 170 
 171         // RLE / blockFlags settings
 172 
 173         logInfo("prism.marlin.forceRLE         = "
 174                 + MarlinProperties.isForceRLE());
 175         logInfo("prism.marlin.forceNoRLE       = "
 176                 + MarlinProperties.isForceNoRLE());
 177         logInfo("prism.marlin.useTileFlags     = "
 178                 + MarlinProperties.isUseTileFlags());
 179         logInfo("prism.marlin.useTileFlags.useHeuristics = "
 180                 + MarlinProperties.isUseTileFlagsWithHeuristics());
 181         logInfo("prism.marlin.rleMinWidth      = "
 182                 + MarlinConst.RLE_MIN_WIDTH);
 183 
 184         // optimisation parameters
 185         logInfo("prism.marlin.useSimplifier    = "
 186                 + MarlinConst.USE_SIMPLIFIER);
 187         logInfo("prism.marlin.usePathSimplifier= "
 188                 + MarlinConst.USE_PATH_SIMPLIFIER);
 189         logInfo("prism.marlin.pathSimplifier.pixTol = "
 190                 + MarlinProperties.getPathSimplifierPixelTolerance());
 191 
 192         logInfo("prism.marlin.clip             = "
 193                 + MarlinProperties.isDoClip());
 194         logInfo("prism.marlin.clip.runtime.enable = "
 195                 + MarlinProperties.isDoClipRuntimeFlag());
 196 
 197         logInfo("prism.marlin.clip.subdivider  = "
 198                 + MarlinProperties.isDoClipSubdivider());
 199         logInfo("prism.marlin.clip.subdivider.minLength = "
 200                 + MarlinProperties.getSubdividerMinLength());
 201 
 202         // debugging parameters
 203         logInfo("prism.marlin.doStats          = "
 204                 + MarlinConst.DO_STATS);
 205         logInfo("prism.marlin.doMonitors       = "
 206                 + MarlinConst.DO_MONITORS);
 207         logInfo("prism.marlin.doChecks         = "
 208                 + MarlinConst.DO_CHECKS);
 209 
 210         // logging parameters
 211         logInfo("prism.marlin.log              = "
 212                 + MarlinConst.ENABLE_LOGS);
 213         logInfo("prism.marlin.useLogger        = "
 214                 + MarlinConst.USE_LOGGER);
 215         logInfo("prism.marlin.logCreateContext = "
 216                 + MarlinConst.LOG_CREATE_CONTEXT);
 217         logInfo("prism.marlin.logUnsafeMalloc  = "
 218                 + MarlinConst.LOG_UNSAFE_MALLOC);
 219 
 220         // quality settings
 221         logInfo("prism.marlin.curve_len_err    = "
 222                 + MarlinProperties.getCurveLengthError());
 223         logInfo("prism.marlin.cubic_dec_d2     = "
 224                 + MarlinProperties.getCubicDecD2());
 225         logInfo("prism.marlin.cubic_inc_d1     = "
 226                 + MarlinProperties.getCubicIncD1());
 227         logInfo("prism.marlin.quad_dec_d2      = "
 228                 + MarlinProperties.getQuadDecD2());
 229 
 230         logInfo("Renderer settings:");
 231         logInfo("CUB_DEC_BND  = " + Renderer.CUB_DEC_BND);
 232         logInfo("CUB_INC_BND  = " + Renderer.CUB_INC_BND);
 233         logInfo("QUAD_DEC_BND = " + Renderer.QUAD_DEC_BND);
 234 
 235         logInfo("INITIAL_EDGES_CAPACITY        = "
 236                 + MarlinConst.INITIAL_EDGES_CAPACITY);
 237         logInfo("INITIAL_CROSSING_COUNT        = "
 238                 + MarlinConst.INITIAL_CROSSING_COUNT);
 239 
 240         logInfo("=========================================================="
 241                 + "=====================");
 242     }
 243 
 244     /**
 245      * Get the RendererContext instance dedicated to the current thread
 246      * @return RendererContext instance
 247      */
 248     @SuppressWarnings({"unchecked"})
 249     public static RendererContext getRendererContext() {
 250         final RendererContext rdrCtx = RDR_CTX_PROVIDER.acquire();
 251         if (DO_MONITORS) {
 252             rdrCtx.stats.mon_pre_getAATileGenerator.start();
 253         }
 254         return rdrCtx;
 255     }
 256 
 257     /**
 258      * Reset and return the given RendererContext instance for reuse
 259      * @param rdrCtx RendererContext instance
 260      */
 261     public static void returnRendererContext(final RendererContext rdrCtx) {
 262         rdrCtx.dispose();
 263 
 264         if (DO_MONITORS) {
 265             rdrCtx.stats.mon_pre_getAATileGenerator.stop();
 266         }
 267         RDR_CTX_PROVIDER.release(rdrCtx);
 268     }
 269 }