/*
 * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.sun.prism.impl;

import com.sun.glass.ui.Application;
import com.sun.glass.ui.Pixels;
import com.sun.prism.PixelSource;
import java.lang.ref.WeakReference;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.List;

Base concrete implementation of the PixelSource interface which manages Pixels objects in the state of being consumed (uploaded to the screen usually), in flight in the queue of upload requests, and idle waiting to be reused for temporary storage for future uploads. All Pixels objects currently saved for reuse will all be the same dimensions and scale which are tracked by calling the validate() method.

At most we will need 3 sets of pixels: One may be "in use", a hard reference stored in beingConsumed Another may be "in the queue", hard ref stored in enqueued A third may be needed to prepare new pixels while those two are in transit. If the third is filled with pixels and enqueued while the previously mentioned two are still in their stages of use, then it will replace the second object as the "enqueued" reference and the previously enqueued object will then become itself the "third unused" reference. If everything happens in lock step we will often have only one set of pixels. If the consumer/displayer gets slightly or occasionally behind we might end up with two sets of pixels in play. Only when things get really bad with multiple deliveries enqueued during the processing of a single earlier delivery will we end up with three sets of Pixels objects in play.

/** * Base concrete implementation of the {@code PixelSource} interface which * manages {@link Pixels} objects in the state of being consumed (uploaded * to the screen usually), in flight in the queue of upload requests, and * idle waiting to be reused for temporary storage for future uploads. * All {@code Pixels} objects currently saved for reuse will all be the * same dimensions and scale which are tracked by calling the * {@link #validate(int, int, float) validate()} method. * <p> * At most we will need 3 sets of pixels: * One may be "in use", a hard reference stored in beingConsumed * Another may be "in the queue", hard ref stored in enqueued * A third may be needed to prepare new pixels while those two are in * transit. * If the third is filled with pixels and enqueued while the previously * mentioned two are still in their stages of use, then it will replace * the second object as the "enqueued" reference and the previously * enqueued object will then become itself the "third unused" reference. * If everything happens in lock step we will often have only one * set of pixels. If the consumer/displayer gets slightly or occasionally * behind we might end up with two sets of pixels in play. Only when things * get really bad with multiple deliveries enqueued during the processing * of a single earlier delivery will we end up with three sets of * {@code Pixels} objects in play. */
public class QueuedPixelSource implements PixelSource { private volatile Pixels beingConsumed; private volatile Pixels enqueued; private final List<WeakReference<Pixels>> saved = new ArrayList<WeakReference<Pixels>>(3); private final boolean useDirectBuffers; public QueuedPixelSource(boolean useDirectBuffers) { this.useDirectBuffers = useDirectBuffers; } @Override public synchronized Pixels getLatestPixels() { if (beingConsumed != null) { throw new IllegalStateException("already consuming pixels: "+beingConsumed); } if (enqueued != null) { beingConsumed = enqueued; enqueued = null; } return beingConsumed; } @Override public synchronized void doneWithPixels(Pixels used) { if (beingConsumed != used) { throw new IllegalStateException("wrong pixels buffer: "+used+" != "+beingConsumed); } beingConsumed = null; } @Override public synchronized void skipLatestPixels() { if (beingConsumed != null) { throw new IllegalStateException("cannot skip while processing: "+beingConsumed); } enqueued = null; } private boolean usesSameBuffer(Pixels p1, Pixels p2) { if (p1 == p2) return true; if (p1 == null || p2 == null) return false; return (p1.getBuffer() == p2.getBuffer()); }
Return an unused Pixels with the indicated dimensions and scale. The returned object may either be saved from a previous use, but currently not being consumed or in the queue. Or it may be an object that reuses a buffer from a previously used (but not active) Pixels object. Or it may be a brand new object.
Params:
  • w – the width of the desired Pixels object
  • h – the height of the desired Pixels object
  • scalex – the horizontal scale of the desired Pixels object
  • scaley – the vertical scale of the desired Pixels object
Returns:an unused Pixels object
/** * Return an unused Pixels with the indicated dimensions and scale. * The returned object may either be saved from a previous use, but * currently not being consumed or in the queue. * Or it may be an object that reuses a buffer from a previously * used (but not active) {@code Pixels} object. * Or it may be a brand new object. * * @param w the width of the desired Pixels object * @param h the height of the desired Pixels object * @param scalex the horizontal scale of the desired Pixels object * @param scaley the vertical scale of the desired Pixels object * @return an unused {@code Pixels} object */
public synchronized Pixels getUnusedPixels(int w, int h, float scalex, float scaley) { int i = 0; IntBuffer reuseBuffer = null; while (i < saved.size()) { WeakReference<Pixels> ref = saved.get(i); Pixels p = ref.get(); if (p == null) { saved.remove(i); continue; } if (usesSameBuffer(p, beingConsumed) || usesSameBuffer(p, enqueued)) { i++; continue; } if (p.getWidthUnsafe() == w && p.getHeightUnsafe() == h && p.getScaleXUnsafe() == scalex && p.getScaleYUnsafe() == scaley) { return p; } // Whether or not we reuse its buffer, this Pixels object is going away. saved.remove(i); reuseBuffer = (IntBuffer) p.getPixels(); if (reuseBuffer.capacity() >= w * h) { break; } reuseBuffer = null; // Loop around and see if there are any other buffers to reuse, // or get rid of all of the buffers that are too small before // we proceed on to the allocation code. } if (reuseBuffer == null) { int bufsize = w * h; if (useDirectBuffers) { reuseBuffer = BufferUtil.newIntBuffer(bufsize); } else { reuseBuffer = IntBuffer.allocate(bufsize); } } Pixels p = Application.GetApplication().createPixels(w, h, reuseBuffer, scalex, scaley); saved.add(new WeakReference<>(p)); return p; }
Place the indicated Pixels object into the enqueued state, replacing any other objects that are currently enqueued but not yet being used by the consumer.
Params:
  • pixels – the Pixels object to be enqueued
/** * Place the indicated {@code Pixels} object into the enqueued state, * replacing any other objects that are currently enqueued but not yet * being used by the consumer. * * @param pixels the {@code Pixels} object to be enqueued */
public synchronized void enqueuePixels(Pixels pixels) { enqueued = pixels; } }