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 }