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     
  52     private volatile float pixScaleFactor = 1.0f;
  53 
  54     UploadingPainter(GlassScene view) {
  55         super(view);
  56     }
  57 
  58     void disposeRTTexture() {
  59         if (rttexture != null) {
  60             rttexture.dispose();
  61             rttexture = null;
  62         }
  63     }
  64     
  65     public void setPixelScaleFactor(float scale) {
  66         pixScaleFactor = scale;
  67     }
  68     
  69     @Override
  70     public float getPixelScaleFactor() {
  71         return pixScaleFactor;
  72     }    
  73 
  74     @Override public void run() {
  75         renderLock.lock();
  76 
  77         boolean valid = false;
  78         boolean errored = false;
  79         try {
  80             valid = validateStageGraphics();
  81 
  82             if (!valid) {
  83                 if (QuantumToolkit.verbose) {
  84                     System.err.println("UploadingPainter: validateStageGraphics failed");
  85                 }
  86                 paintImpl(null);
  87                 return;
  88             }
  89             
  90             if (factory == null) {
  91                 factory = GraphicsPipeline.getDefaultResourceFactory();
  92             }
  93             if (factory == null || !factory.isDeviceReady()) {
  94                 return;
  95             }
  96             
  97             float scale = pixScaleFactor;
  98             
  99             boolean needsReset = (pix == null) ||
 100                                  (scale != pix.getScaleUnsafe()) ||
 101                                  (viewWidth != penWidth) || (viewHeight != penHeight);
 102             
 103             if (!needsReset) {
 104                 rttexture.lock();
 105                 if (rttexture.isSurfaceLost()) {
 106                     rttexture.unlock();
 107                     sceneState.getScene().entireSceneNeedsRepaint();
 108                     needsReset = true;
 109                 }
 110             }
 111             
 112             int bufWidth = (int)Math.round(viewWidth * scale);
 113             int bufHeight = (int)Math.round(viewHeight * scale);
 114             
 115             if (needsReset) {
 116                 disposeRTTexture();
 117                 rttexture = factory.createRTTexture(bufWidth, bufHeight, WrapMode.CLAMP_NOT_NEEDED);
 118                 if (rttexture == null) {
 119                     return;
 120                 }
 121                 penWidth    = viewWidth;
 122                 penHeight   = viewHeight;
 123                 textureBits = null;
 124                 pixBits = null;
 125                 freshBackBuffer = true;
 126             }
 127             Graphics g = rttexture.createGraphics();
 128             if (g == null) {
 129                 disposeRTTexture();
 130                 sceneState.getScene().entireSceneNeedsRepaint();
 131                 return;
 132             }
 133             g.scale(scale, scale);
 134             paintImpl(g);
 135             freshBackBuffer = false;
 136 
 137             int rawbits[] = rttexture.getPixels();
 138             
 139             if (rawbits != null) {
 140                 if (pixBits == null || uploadCount.get() > 0) {
 141                     pixBits = IntBuffer.allocate(bufWidth * bufHeight);
 142                 }
 143                 System.arraycopy(rawbits, 0, pixBits.array(), 0, bufWidth * bufHeight);
 144                 pix = app.createPixels(bufWidth, bufHeight, pixBits, scale);
 145             } else {
 146                 if (textureBits == null || uploadCount.get() > 0) {
 147                     textureBits = BufferUtil.newIntBuffer(bufWidth * bufHeight);
 148                 }
 149                 
 150                 if (textureBits != null) {
 151                     if (rttexture.readPixels(textureBits)) {
 152                         pix = app.createPixels(bufWidth, bufHeight, textureBits, scale);
 153                     } else {
 154                         /* device lost */
 155                         sceneState.getScene().entireSceneNeedsRepaint();
 156                         disposeRTTexture();
 157                         pix = null;
 158                     }
 159                 }
 160             }
 161 
 162             if (rttexture != null) {
 163                 rttexture.unlock();
 164             }
 165 
 166             if (pix != null) {
 167                 /* transparent pixels created and ready for upload */
 168                 // Copy references, which are volatile, used by upload. Thus
 169                 // ensure they still exist once event queue is consumed.
 170                 uploadCount.incrementAndGet();
 171                 sceneState.uploadPixels(pix, uploadCount);
 172             }
 173                 
 174         } catch (Throwable th) {
 175             errored = true;
 176             th.printStackTrace(System.err);
 177         } finally {
 178             if (rttexture != null && rttexture.isLocked()) {
 179                 rttexture.unlock();
 180             }
 181 
 182             Disposer.cleanUp();
 183 
 184             sceneState.getScene().setPainting(false);
 185 
 186             factory.getTextureResourcePool().freeDisposalRequestedAndCheckResources(errored);
 187 
 188             renderLock.unlock();
 189         }
 190     }
 191 }