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 }