1 /*
   2  * Copyright (c) 2011, 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.javafx.tk.quantum;
  27 
  28 import java.nio.IntBuffer;
  29 import com.sun.glass.ui.Pixels;
  30 import com.sun.prism.Graphics;
  31 import com.sun.prism.GraphicsPipeline;
  32 import com.sun.prism.RTTexture;
  33 import com.sun.prism.Texture.WrapMode;
  34 import com.sun.prism.impl.Disposer;
  35 import com.sun.prism.impl.QueuedPixelSource;
  36 
  37 /**
  38  * UploadingPainter is used when we need to render into an offscreen buffer.
  39  * The PresentingPainter is used when we are rendering to the main screen.
  40  */
  41 final class UploadingPainter extends ViewPainter implements Runnable {
  42 
  43     private RTTexture   rttexture;
  44     // resolveRTT is a temporary render target to "resolve" a msaa render buffer
  45     // into a normal color render target.
  46     private RTTexture   resolveRTT = null;
  47 
  48     private QueuedPixelSource pixelSource = new QueuedPixelSource(true);
  49     private float penScale;
  50 
  51     UploadingPainter(GlassScene view) {
  52         super(view);
  53     }
  54 
  55     void disposeRTTexture() {
  56         if (rttexture != null) {
  57             rttexture.dispose();
  58             rttexture = null;
  59         }
  60         if (resolveRTT != null) {
  61             resolveRTT.dispose();
  62             resolveRTT = null;
  63         }
  64     }
  65 
  66     @Override
  67     public float getPixelScaleFactor() {
  68         return sceneState.getRenderScale();
  69     }
  70 
  71     @Override public void run() {
  72         renderLock.lock();
  73 
  74         boolean errored = false;
  75         try {
  76             if (!validateStageGraphics()) {
  77                 if (QuantumToolkit.verbose) {
  78                     System.err.println("UploadingPainter: validateStageGraphics failed");
  79                 }
  80                 paintImpl(null);
  81                 return;
  82             }
  83 
  84             if (factory == null) {
  85                 factory = GraphicsPipeline.getDefaultResourceFactory();
  86             }
  87             if (factory == null || !factory.isDeviceReady()) {
  88                 return;
  89             }
  90 
  91             float scale = getPixelScaleFactor();
  92             int bufWidth = sceneState.getRenderWidth();
  93             int bufHeight = sceneState.getRenderHeight();
  94 
  95             // Repaint everything on pen scale or view size change because
  96             // texture contents are no longer correct.
  97             // Repaint everything on new texture dimensions because otherwise
  98             // our upload logic below may fail with index out of bounds.
  99             boolean needsReset = (penScale != scale ||
 100                                   penWidth != viewWidth ||
 101                                   penHeight != viewHeight ||
 102                                   rttexture == null ||
 103                                   rttexture.getContentWidth() != bufWidth ||
 104                                   rttexture.getContentHeight() != bufHeight);
 105 
 106             if (!needsReset) {
 107                 rttexture.lock();
 108                 if (rttexture.isSurfaceLost()) {
 109                     rttexture.unlock();
 110                     sceneState.getScene().entireSceneNeedsRepaint();
 111                     needsReset = true;
 112                 }
 113             }
 114 
 115             if (needsReset) {
 116                 disposeRTTexture();
 117                 rttexture = factory.createRTTexture(bufWidth, bufHeight, WrapMode.CLAMP_NOT_NEEDED,
 118                         sceneState.isMSAA());
 119                 if (rttexture == null) {
 120                     return;
 121                 }
 122                 penScale    = scale;
 123                 penWidth    = viewWidth;
 124                 penHeight   = viewHeight;
 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 outWidth = sceneState.getOutputWidth();
 138             int outHeight = sceneState.getOutputHeight();
 139             float outScale = sceneState.getOutputScale();
 140             RTTexture rtt;
 141             if (rttexture.isMSAA() || outWidth != bufWidth || outHeight != bufHeight) {
 142                 rtt = resolveRenderTarget(g, outWidth, outHeight);
 143             } else {
 144                 rtt = rttexture;
 145             }
 146 
 147             Pixels pix = pixelSource.getUnusedPixels(outWidth, outHeight, outScale);
 148             IntBuffer bits = (IntBuffer) pix.getPixels();
 149 
 150             int rawbits[] = rtt.getPixels();
 151 
 152             if (rawbits != null) {
 153                 bits.put(rawbits, 0, outWidth * outHeight);
 154             } else {
 155                 if (!rtt.readPixels(bits)) {
 156                     /* device lost */
 157                     sceneState.getScene().entireSceneNeedsRepaint();
 158                     disposeRTTexture();
 159                     pix = null;
 160                 }
 161             }
 162 
 163             if (rttexture != null) {
 164                 rttexture.unlock();
 165             }
 166 
 167             if (pix != null) {
 168                 /* transparent pixels created and ready for upload */
 169                 // Copy references, which are volatile, used by upload. Thus
 170                 // ensure they still exist once event queue is consumed.
 171                 pixelSource.enqueuePixels(pix);
 172                 sceneState.uploadPixels(pixelSource);
 173             }
 174 
 175         } catch (Throwable th) {
 176             errored = true;
 177             th.printStackTrace(System.err);
 178         } finally {
 179             if (rttexture != null && rttexture.isLocked()) {
 180                 rttexture.unlock();
 181             }
 182             if (resolveRTT != null && resolveRTT.isLocked()) {
 183                 resolveRTT.unlock();
 184             }
 185 
 186             Disposer.cleanUp();
 187 
 188             sceneState.getScene().setPainting(false);
 189 
 190             if (factory != null) {
 191                 factory.getTextureResourcePool().freeDisposalRequestedAndCheckResources(errored);
 192             }
 193 
 194             renderLock.unlock();
 195         }
 196     }
 197 
 198     private RTTexture resolveRenderTarget(Graphics g, int width, int height) {
 199         if (resolveRTT != null) {
 200             resolveRTT.lock();
 201             if (resolveRTT.isSurfaceLost() ||
 202                 resolveRTT.getContentWidth() != width ||
 203                 resolveRTT.getContentHeight() != height)
 204             {
 205                 resolveRTT.unlock();
 206                 resolveRTT.dispose();
 207                 resolveRTT = null;
 208             }
 209         }
 210         if (resolveRTT == null) {
 211             resolveRTT = g.getResourceFactory().createRTTexture(
 212                     width, height,
 213                     WrapMode.CLAMP_NOT_NEEDED, false);
 214         }
 215         int srcw = rttexture.getContentWidth();
 216         int srch = rttexture.getContentHeight();
 217         g.blit(rttexture, resolveRTT, 0, 0, srcw, srch, 0, 0, width, height);
 218         return resolveRTT;
 219     }
 220 }