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 if (factory != null) { 187 factory.getTextureResourcePool().freeDisposalRequestedAndCheckResources(errored); 188 } 189 190 renderLock.unlock(); 191 } 192 } 193 }