1 /*
   2  * Copyright (c) 2011, 2014, 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.javafx.tk.quantum;
  27 
  28 import java.nio.IntBuffer;
  29 import java.util.concurrent.atomic.AtomicInteger;
  30 import com.sun.glass.ui.Application;
  31 import com.sun.glass.ui.Pixels;
  32 import com.sun.prism.Graphics;
  33 import com.sun.prism.GraphicsPipeline;
  34 import com.sun.prism.RTTexture;
  35 import com.sun.prism.Texture.WrapMode;
  36 import com.sun.prism.impl.BufferUtil;
  37 import com.sun.prism.impl.Disposer;
  38 
  39 /**
  40  * UploadingPainter is used when we need to render into an offscreen buffer.
  41  * The PresentingPainter is used when we are rendering to the main screen.
  42  */
  43 final class UploadingPainter extends ViewPainter implements Runnable {
  44 
  45     private Application app = Application.GetApplication();
  46     private Pixels      pix;
  47     private IntBuffer   textureBits; // Used for RTTs that are not backed by a SW array
  48     private IntBuffer   pixBits; // Users for RTTs that are backed by a SW array
  49     private final AtomicInteger uploadCount = new AtomicInteger(0);
  50     private RTTexture   rttexture;
  51     // resolveRTT is a temporary render target to "resolve" a msaa render buffer
  52     // into a normal color render target.
  53     // REMIND: resolveRTT could be a single shared scratch rtt
  54     private RTTexture   resolveRTT = null;
  55     
  56     private volatile float pixScaleFactor = 1.0f;
  57 
  58     UploadingPainter(GlassScene view) {
  59         super(view);
  60     }
  61 
  62     void disposeRTTexture() {
  63         if (rttexture != null) {
  64             rttexture.dispose();
  65             rttexture = null;
  66         }
  67         if (resolveRTT != null) {
  68             resolveRTT.dispose();
  69             resolveRTT = null;
  70         }
  71     }
  72     
  73     public void setPixelScaleFactor(float scale) {
  74         pixScaleFactor = scale;
  75     }
  76     
  77     @Override
  78     public float getPixelScaleFactor() {
  79         return pixScaleFactor;
  80     }    
  81 
  82     @Override public void run() {
  83         renderLock.lock();
  84 
  85         boolean valid = false;
  86         boolean errored = false;
  87         try {
  88             valid = validateStageGraphics();
  89 
  90             if (!valid) {
  91                 if (QuantumToolkit.verbose) {
  92                     System.err.println("UploadingPainter: validateStageGraphics failed");
  93                 }
  94                 paintImpl(null);
  95                 return;
  96             }
  97             
  98             if (factory == null) {
  99                 factory = GraphicsPipeline.getDefaultResourceFactory();
 100             }
 101             if (factory == null || !factory.isDeviceReady()) {
 102                 return;
 103             }
 104             
 105             float scale = pixScaleFactor;
 106             
 107             boolean needsReset = (pix == null) ||
 108                                  (scale != pix.getScaleUnsafe()) ||
 109                                  (viewWidth != penWidth) || (viewHeight != penHeight);
 110             
 111             if (!needsReset) {
 112                 rttexture.lock();
 113                 if (rttexture.isSurfaceLost()) {
 114                     rttexture.unlock();
 115                     sceneState.getScene().entireSceneNeedsRepaint();
 116                     needsReset = true;
 117                 }
 118             }
 119             
 120             int bufWidth = (int)Math.round(viewWidth * scale);
 121             int bufHeight = (int)Math.round(viewHeight * scale);
 122             
 123             if (needsReset) {
 124                 disposeRTTexture();
 125                 rttexture = factory.createRTTexture(bufWidth, bufHeight, WrapMode.CLAMP_NOT_NEEDED,
 126                         sceneState.isAntiAliasing());
 127                 if (rttexture == null) {
 128                     return;
 129                 }
 130                 penWidth    = viewWidth;
 131                 penHeight   = viewHeight;
 132                 textureBits = null;
 133                 pixBits = null;
 134                 freshBackBuffer = true;
 135             }
 136             Graphics g = rttexture.createGraphics();
 137             if (g == null) {
 138                 disposeRTTexture();
 139                 sceneState.getScene().entireSceneNeedsRepaint();
 140                 return;
 141             }
 142             g.scale(scale, scale);
 143             paintImpl(g);
 144             freshBackBuffer = false;
 145 
 146             int rawbits[] = rttexture.getPixels();
 147             
 148             if (rawbits != null) {
 149                 if (pixBits == null || uploadCount.get() > 0) {
 150                     pixBits = IntBuffer.allocate(bufWidth * bufHeight);
 151                 }
 152                 System.arraycopy(rawbits, 0, pixBits.array(), 0, bufWidth * bufHeight);
 153                 pix = app.createPixels(bufWidth, bufHeight, pixBits, scale);
 154             } else {
 155                 if (textureBits == null || uploadCount.get() > 0) {
 156                     textureBits = BufferUtil.newIntBuffer(bufWidth * bufHeight);
 157                 }
 158                 
 159                 if (textureBits != null) {
 160                     RTTexture rtt = rttexture.isAntiAliasing() ?
 161                         resolveRenderTarget(g) : rttexture;
 162 
 163                     if (rtt.readPixels(textureBits)) {
 164                         pix = app.createPixels(bufWidth, bufHeight, textureBits, scale);
 165                     } else {
 166                         /* device lost */
 167                         sceneState.getScene().entireSceneNeedsRepaint();
 168                         disposeRTTexture();
 169                         pix = null;
 170                     }
 171                 }
 172             }
 173 
 174             if (rttexture != null) {
 175                 rttexture.unlock();
 176             }
 177 
 178             if (pix != null) {
 179                 /* transparent pixels created and ready for upload */
 180                 // Copy references, which are volatile, used by upload. Thus
 181                 // ensure they still exist once event queue is consumed.
 182                 uploadCount.incrementAndGet();
 183                 sceneState.uploadPixels(pix, uploadCount);
 184             }
 185                 
 186         } catch (Throwable th) {
 187             errored = true;
 188             th.printStackTrace(System.err);
 189         } finally {
 190             if (rttexture != null && rttexture.isLocked()) {
 191                 rttexture.unlock();
 192             }
 193             if (resolveRTT != null && resolveRTT.isLocked()) {
 194                 resolveRTT.unlock();
 195             }
 196 
 197             Disposer.cleanUp();
 198 
 199             sceneState.getScene().setPainting(false);
 200 
 201             if (factory != null) {
 202                 factory.getTextureResourcePool().freeDisposalRequestedAndCheckResources(errored);
 203             }
 204 
 205             renderLock.unlock();
 206         }
 207     }
 208 
 209     private RTTexture resolveRenderTarget(Graphics g) {
 210         int width = rttexture.getContentWidth();
 211         int height = rttexture.getContentHeight();
 212         if (resolveRTT != null &&
 213                 (resolveRTT.getContentWidth() != width ||
 214                 (resolveRTT.getContentHeight() != height)))
 215         {
 216             // If msaa rtt is not the same size than resolve buffer, then dispose
 217             resolveRTT.dispose();
 218             resolveRTT = null;
 219         }
 220         if (resolveRTT == null || resolveRTT.isSurfaceLost()) {
 221             resolveRTT = g.getResourceFactory().createRTTexture(
 222                     width, height,
 223                     WrapMode.CLAMP_NOT_NEEDED, false);
 224         } else {
 225             resolveRTT.lock();
 226         }
 227         g.blit(rttexture, resolveRTT, 0, 0, width, height, 0, 0, width, height);
 228         return resolveRTT;
 229     }
 230 }