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.prism.impl; 27 28 import com.sun.glass.ui.Pixels; 29 import com.sun.prism.PixelSource; 30 import java.lang.ref.WeakReference; 31 import java.util.ArrayList; 32 import java.util.List; 33 34 /** 35 * Base concrete implementation of the {@code PixelSource} interface which 36 * manages {@link Pixels} objects in the state of being consumed (uploaded 37 * to the screen usually), in flight in the queue of upload requests, and 38 * idle waiting to be reused for temporary storage for future uploads. 39 * All {@code Pixels} objects currently saved for reuse will all be the 40 * same dimensions and scale which are tracked by calling the 41 * {@link #validate(int, int, float) validate()} method. 42 * <p> 43 * At most we will need 3 sets of pixels: 44 * One may be "in use", a hard reference stored in beingConsumed 45 * Another may be "in the queue", hard ref stored in enqueued 46 * A third may be needed to prepare new pixels while those two are in 47 * transit. 48 * If the third is filled with pixels and enqueued while the previously 49 * mentioned two are still in their stages of use, then it will replace 50 * the second object as the "enqueued" reference and the previously 51 * enqueued object will then become itself the "third unused" reference. 52 * If everything happens in lock step we will often have only one 53 * set of pixels. If the consumer/displayer gets slightly or occasionally 54 * behind we might end up with two sets of pixels in play. Only when things 55 * get really bad with multiple deliveries enqueued during the processing 56 * of a single earlier delivery will we end up with three sets of 57 * {@code Pixels} objects in play. 58 */ 59 public class QueuedPixelSource implements PixelSource { 60 private volatile Pixels beingConsumed; 61 private volatile Pixels enqueued; 62 private final List<WeakReference<Pixels>> saved = 63 new ArrayList<WeakReference<Pixels>>(3); 64 private int pixelW; 65 private int pixelH; 66 private float pixelScale; 67 68 @Override 69 public synchronized Pixels getLatestPixels() { 70 if (beingConsumed != null) { 71 throw new IllegalStateException("already consuming pixels: "+beingConsumed); 72 } 73 if (enqueued != null) { 74 beingConsumed = enqueued; 75 enqueued = null; 76 } 77 return beingConsumed; 78 } 79 80 @Override 81 public synchronized void doneWithPixels(Pixels used) { 82 if (beingConsumed != used) { 83 throw new IllegalStateException("wrong pixels buffer: "+used+" != "+beingConsumed); 84 } 85 beingConsumed = null; 86 } 87 88 @Override 89 public synchronized void skipLatestPixels() { 90 if (beingConsumed != null) { 91 throw new IllegalStateException("cannot skip while processing: "+beingConsumed); 92 } 93 enqueued = null; 94 } 95 96 /** 97 * Validates the saved pixels objects against the specified dimensions 98 * and pixel scale and returns a boolean indicating if the pixel buffers 99 * are still valid. 100 * This method may free old saved buffers so that they will not be reused, 101 * but it will leave the existing enqueued buffers alone until they are 102 * eventually replaced. 103 * 104 * @param w the intended width of the {@code Pixels} objects 105 * @param h the intended height of the {@code Pixels} objects 106 * @param scale the intended pixel scale of the {@code Pixels} objects 107 * @return 108 */ 109 public synchronized boolean validate(int w, int h, float scale) { 110 if (w != pixelW || h != pixelH || scale != pixelScale) { 111 saved.clear(); 112 pixelW = w; 113 pixelH = h; 114 pixelScale = scale; 115 return false; 116 } 117 return true; 118 } 119 120 /** 121 * Return an unused Pixels object previously used with this 122 * {@code PixelSource}, or null if there are none. 123 * The caller should create a new {@code Pixels} object if 124 * this method returns null and register it with a call 125 * to {@link #enqueuePixels(com.sun.glass.ui.Pixels) enqueuePixels()} 126 * when it is filled with data. 127 * 128 * @return an unused {@code Pixels} object or null if the caller 129 * should create a new one 130 */ 131 public synchronized Pixels getUnusedPixels() { 132 int i = 0; 133 while (i < saved.size()) { 134 WeakReference<Pixels> ref = saved.get(i); 135 Pixels p = ref.get(); 136 if (p == null) { 137 saved.remove(i); 138 continue; 139 } 140 if (p != beingConsumed && p != enqueued) { 141 assert(p.getWidthUnsafe() == pixelW && 142 p.getHeightUnsafe() == pixelH && 143 p.getScaleUnsafe() == pixelScale); 144 return p; 145 } 146 i++; 147 } 148 return null; 149 } 150 151 /** 152 * Place the indicated {@code Pixels} object into the enqueued state, 153 * replacing any other objects that are currently enqueued but not yet 154 * being used by the consumer, and register the object for later 155 * reuse. 156 * 157 * @param pixels the {@code Pixels} object to be enqueued (and saved for reuse) 158 */ 159 public synchronized void enqueuePixels(Pixels pixels) { 160 if (pixels.getWidthUnsafe() != pixelW || 161 pixels.getHeightUnsafe() != pixelH || 162 pixels.getScaleUnsafe() != pixelScale) 163 { 164 throw new IllegalArgumentException("Pixels object: "+pixels+ 165 "does not match validated parameters: "+ 166 pixelW+" x "+pixelH+" @ "+pixelScale+"x"); 167 } 168 enqueued = pixels; 169 // Now make sure it is in our saved array since this could be 170 // the first time we have seen this particular storage object. 171 int i = 0; 172 while (i < saved.size()) { 173 WeakReference<Pixels> ref = saved.get(i); 174 Pixels p = ref.get(); 175 if (p == null) { 176 saved.remove(i); 177 continue; 178 } 179 if (p == pixels) { 180 // Found it - already known. 181 return; 182 } 183 i++; 184 } 185 // Did not find it, this must be a new storage object. 186 if (saved.size() >= 3) { 187 throw new InternalError("too many Pixels objects saved"); 188 } 189 saved.add(new WeakReference<Pixels>(pixels)); 190 } 191 } | 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.prism.impl; 27 28 import com.sun.glass.ui.Application; 29 import com.sun.glass.ui.Pixels; 30 import com.sun.prism.PixelSource; 31 import java.lang.ref.WeakReference; 32 import java.nio.IntBuffer; 33 import java.util.ArrayList; 34 import java.util.List; 35 36 /** 37 * Base concrete implementation of the {@code PixelSource} interface which 38 * manages {@link Pixels} objects in the state of being consumed (uploaded 39 * to the screen usually), in flight in the queue of upload requests, and 40 * idle waiting to be reused for temporary storage for future uploads. 41 * All {@code Pixels} objects currently saved for reuse will all be the 42 * same dimensions and scale which are tracked by calling the 43 * {@link #validate(int, int, float) validate()} method. 44 * <p> 45 * At most we will need 3 sets of pixels: 46 * One may be "in use", a hard reference stored in beingConsumed 47 * Another may be "in the queue", hard ref stored in enqueued 48 * A third may be needed to prepare new pixels while those two are in 49 * transit. 50 * If the third is filled with pixels and enqueued while the previously 51 * mentioned two are still in their stages of use, then it will replace 52 * the second object as the "enqueued" reference and the previously 53 * enqueued object will then become itself the "third unused" reference. 54 * If everything happens in lock step we will often have only one 55 * set of pixels. If the consumer/displayer gets slightly or occasionally 56 * behind we might end up with two sets of pixels in play. Only when things 57 * get really bad with multiple deliveries enqueued during the processing 58 * of a single earlier delivery will we end up with three sets of 59 * {@code Pixels} objects in play. 60 */ 61 public class QueuedPixelSource implements PixelSource { 62 private volatile Pixels beingConsumed; 63 private volatile Pixels enqueued; 64 private final List<WeakReference<Pixels>> saved = 65 new ArrayList<WeakReference<Pixels>>(3); 66 private final boolean useDirectBuffers; 67 68 public QueuedPixelSource(boolean useDirectBuffers) { 69 this.useDirectBuffers = useDirectBuffers; 70 } 71 72 @Override 73 public synchronized Pixels getLatestPixels() { 74 if (beingConsumed != null) { 75 throw new IllegalStateException("already consuming pixels: "+beingConsumed); 76 } 77 if (enqueued != null) { 78 beingConsumed = enqueued; 79 enqueued = null; 80 } 81 return beingConsumed; 82 } 83 84 @Override 85 public synchronized void doneWithPixels(Pixels used) { 86 if (beingConsumed != used) { 87 throw new IllegalStateException("wrong pixels buffer: "+used+" != "+beingConsumed); 88 } 89 beingConsumed = null; 90 } 91 92 @Override 93 public synchronized void skipLatestPixels() { 94 if (beingConsumed != null) { 95 throw new IllegalStateException("cannot skip while processing: "+beingConsumed); 96 } 97 enqueued = null; 98 } 99 100 private boolean usesSameBuffer(Pixels p1, Pixels p2) { 101 if (p1 == p2) return true; 102 if (p1 == null || p2 == null) return false; 103 return (p1.getPixels() == p2.getPixels()); 104 } 105 106 /** 107 * Return an unused Pixels with the indicated dimensions and scale. 108 * The returned object may either be saved from a previous use, but 109 * currently not being consumed or in the queue. 110 * Or it may be an object that reuses a buffer from a previously 111 * used (but not active) {@code Pixels} object. 112 * Or it may be a brand new object. 113 * 114 * @param w the width of the desired Pixels object 115 * @param h the height of the desired Pixels object 116 * @param scale the scale of the desired Pixels object 117 * @return an unused {@code Pixels} object 118 */ 119 public synchronized Pixels getUnusedPixels(int w, int h, float scale) { 120 int i = 0; 121 IntBuffer reuseBuffer = null; 122 while (i < saved.size()) { 123 WeakReference<Pixels> ref = saved.get(i); 124 Pixels p = ref.get(); 125 if (p == null) { 126 saved.remove(i); 127 continue; 128 } 129 if (usesSameBuffer(p, beingConsumed) || usesSameBuffer(p, enqueued)) { 130 i++; 131 continue; 132 } 133 if (p.getWidthUnsafe() == w && 134 p.getHeightUnsafe() == h && 135 p.getScaleUnsafe() == scale) 136 { 137 return p; 138 } 139 // Whether or not we reuse its buffer, this Pixels object is going away. 140 saved.remove(i); 141 reuseBuffer = (IntBuffer) p.getPixels(); 142 if (reuseBuffer.capacity() >= w * h) { 143 break; 144 } 145 reuseBuffer = null; 146 // Loop around and see if there are any other buffers to reuse, 147 // or get rid of all of the buffers that are too small before 148 // we proceed on to the allocation code. 149 } 150 if (reuseBuffer == null) { 151 int bufsize = w * h; 152 if (useDirectBuffers) { 153 reuseBuffer = BufferUtil.newIntBuffer(bufsize); 154 } else { 155 reuseBuffer = IntBuffer.allocate(bufsize); 156 } 157 } 158 Pixels p = Application.GetApplication().createPixels(w, h, reuseBuffer, scale); 159 saved.add(new WeakReference<>(p)); 160 return p; 161 } 162 163 /** 164 * Place the indicated {@code Pixels} object into the enqueued state, 165 * replacing any other objects that are currently enqueued but not yet 166 * being used by the consumer. 167 * 168 * @param pixels the {@code Pixels} object to be enqueued 169 */ 170 public synchronized void enqueuePixels(Pixels pixels) { 171 enqueued = pixels; 172 } 173 } |