jdk/src/share/classes/sun/java2d/pipe/RenderQueue.java
changeset 2 90ce3da70b43
child 5506 202f599c92aa
equal deleted inserted replaced
0:fd16c54261b3 2:90ce3da70b43
       
     1 /*
       
     2  * Copyright 2005 Sun Microsystems, Inc.  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.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 package sun.java2d.pipe;
       
    27 
       
    28 import java.util.HashSet;
       
    29 import java.util.Set;
       
    30 import sun.awt.SunToolkit;
       
    31 
       
    32 /**
       
    33  * The RenderQueue class encapsulates a RenderBuffer on which rendering
       
    34  * operations are enqueued.  Note that the RenderQueue lock must be acquired
       
    35  * before performing any operations on the queue (e.g. enqueuing an operation
       
    36  * or flushing the queue).  A sample usage scenario follows:
       
    37  *
       
    38  *     public void drawSomething(...) {
       
    39  *         rq.lock();
       
    40  *         try {
       
    41  *             ctx.validate(...);
       
    42  *             rq.ensureCapacity(4);
       
    43  *             rq.getBuffer().putInt(DRAW_SOMETHING);
       
    44  *             ...
       
    45  *         } finally {
       
    46  *             rq.unlock();
       
    47  *         }
       
    48  *     }
       
    49  *
       
    50  * If you are enqueuing an operation that involves 8-byte parameters (i.e.
       
    51  * long or double values), it is imperative that you ensure proper
       
    52  * alignment of the underlying RenderBuffer.  This can be accomplished
       
    53  * simply by providing an offset to the first 8-byte parameter in your
       
    54  * operation to the ensureCapacityAndAlignment() method.  For example:
       
    55  *
       
    56  *     public void drawStuff(...) {
       
    57  *         rq.lock();
       
    58  *         try {
       
    59  *             RenderBuffer buf = rq.getBuffer();
       
    60  *             ctx.validate(...);
       
    61  *             // 28 total bytes in the operation, 12 bytes to the first long
       
    62  *             rq.ensureCapacityAndAlignment(28, 12);
       
    63  *             buf.putInt(DRAW_STUFF);
       
    64  *             buf.putInt(x).putInt(y);
       
    65  *             buf.putLong(addr1);
       
    66  *             buf.putLong(addr2);
       
    67  *         } finally {
       
    68  *             rq.unlock();
       
    69  *         }
       
    70  *     }
       
    71  */
       
    72 public abstract class RenderQueue {
       
    73 
       
    74     /** The size of the underlying buffer, in bytes. */
       
    75     private static final int BUFFER_SIZE = 32000;
       
    76 
       
    77     /** The underlying buffer for this queue. */
       
    78     protected RenderBuffer buf;
       
    79 
       
    80     /**
       
    81      * A Set containing hard references to Objects that must stay alive until
       
    82      * the queue has been completely flushed.
       
    83      */
       
    84     protected Set refSet;
       
    85 
       
    86     protected RenderQueue() {
       
    87         refSet = new HashSet();
       
    88         buf = RenderBuffer.allocate(BUFFER_SIZE);
       
    89     }
       
    90 
       
    91     /**
       
    92      * Locks the queue for read/write access.
       
    93      */
       
    94     public final void lock() {
       
    95         /*
       
    96          * Implementation note: In theory we should have two separate locks:
       
    97          * one lock to synchronize access to the RenderQueue, and then a
       
    98          * separate lock (the AWT lock) that only needs to be acquired when
       
    99          * we are about to flush the queue (using native windowing system
       
   100          * operations).  In practice it has been difficult to enforce the
       
   101          * correct lock ordering; sometimes AWT will have already acquired
       
   102          * the AWT lock before grabbing the RQ lock (see 6253009), while the
       
   103          * expected order should be RQ lock and then AWT lock.  Due to this
       
   104          * issue, using two separate locks is prone to deadlocks.  Therefore,
       
   105          * to solve this issue we have decided to eliminate the separate RQ
       
   106          * lock and instead just acquire the AWT lock here.  (Someday it might
       
   107          * be nice to go back to the old two-lock system, but that would
       
   108          * require potentially risky changes to AWT to ensure that it never
       
   109          * acquires the AWT lock before calling into 2D code that wants to
       
   110          * acquire the RQ lock.)
       
   111          */
       
   112         SunToolkit.awtLock();
       
   113     }
       
   114 
       
   115     /**
       
   116      * Attempts to lock the queue.  If successful, this method returns true,
       
   117      * indicating that the caller is responsible for calling
       
   118      * <code>unlock</code>; otherwise this method returns false.
       
   119      */
       
   120     public final boolean tryLock() {
       
   121         return SunToolkit.awtTryLock();
       
   122     }
       
   123 
       
   124     /**
       
   125      * Unlocks the queue.
       
   126      */
       
   127     public final void unlock() {
       
   128         SunToolkit.awtUnlock();
       
   129     }
       
   130 
       
   131     /**
       
   132      * Adds the given Object to the set of hard references, which will
       
   133      * prevent that Object from being disposed until the queue has been
       
   134      * flushed completely.  This is useful in cases where some enqueued
       
   135      * data could become invalid if the reference Object were garbage
       
   136      * collected before the queue could be processed.  (For example, keeping
       
   137      * a hard reference to a FontStrike will prevent any enqueued glyph
       
   138      * images associated with that strike from becoming invalid before the
       
   139      * queue is flushed.)  The reference set will be cleared immediately
       
   140      * after the queue is flushed each time.
       
   141      */
       
   142     public final void addReference(Object ref) {
       
   143         refSet.add(ref);
       
   144     }
       
   145 
       
   146     /**
       
   147      * Returns the encapsulated RenderBuffer object.
       
   148      */
       
   149     public final RenderBuffer getBuffer() {
       
   150         return buf;
       
   151     }
       
   152 
       
   153     /**
       
   154      * Ensures that there will be enough room on the underlying buffer
       
   155      * for the following operation.  If the operation will not fit given
       
   156      * the remaining space, the buffer will be flushed immediately, leaving
       
   157      * an empty buffer for the impending operation.
       
   158      *
       
   159      * @param opsize size (in bytes) of the following operation
       
   160      */
       
   161     public final void ensureCapacity(int opsize) {
       
   162         if (buf.remaining() < opsize) {
       
   163             flushNow();
       
   164         }
       
   165     }
       
   166 
       
   167     /**
       
   168      * Convenience method that is equivalent to calling ensureCapacity()
       
   169      * followed by ensureAlignment().  The ensureCapacity() call allows for an
       
   170      * extra 4 bytes of space in case the ensureAlignment() method needs to
       
   171      * insert a NOOP token on the buffer.
       
   172      *
       
   173      * @param opsize size (in bytes) of the following operation
       
   174      * @param first8ByteValueOffset offset (in bytes) from the current
       
   175      * position to the first 8-byte value used in the following operation
       
   176      */
       
   177     public final void ensureCapacityAndAlignment(int opsize,
       
   178                                                  int first8ByteValueOffset)
       
   179     {
       
   180         ensureCapacity(opsize + 4);
       
   181         ensureAlignment(first8ByteValueOffset);
       
   182     }
       
   183 
       
   184     /**
       
   185      * Inserts a 4-byte NOOP token when necessary to ensure that all 8-byte
       
   186      * parameters for the following operation are added to the underlying
       
   187      * buffer with an 8-byte memory alignment.
       
   188      *
       
   189      * @param first8ByteValueOffset offset (in bytes) from the current
       
   190      * position to the first 8-byte value used in the following operation
       
   191      */
       
   192     public final void ensureAlignment(int first8ByteValueOffset) {
       
   193         int first8ByteValuePosition = buf.position() + first8ByteValueOffset;
       
   194         if ((first8ByteValuePosition & 7) != 0) {
       
   195             buf.putInt(BufferedOpCodes.NOOP);
       
   196         }
       
   197     }
       
   198 
       
   199     /**
       
   200      * Immediately processes each operation currently pending on the buffer.
       
   201      * This method will block until the entire buffer has been flushed.  The
       
   202      * queue lock must be acquired before calling this method.
       
   203      */
       
   204     public abstract void flushNow();
       
   205 
       
   206     /**
       
   207      * Immediately processes each operation currently pending on the buffer,
       
   208      * and then invokes the provided task.  This method will block until the
       
   209      * entire buffer has been flushed and the provided task has been executed.
       
   210      * The queue lock must be acquired before calling this method.
       
   211      */
       
   212     public abstract void flushAndInvokeNow(Runnable task);
       
   213 
       
   214     /**
       
   215      * Updates the current position of the underlying buffer, and then
       
   216      * flushes the queue immediately.  This method is useful when native code
       
   217      * has added data to the queue and needs to flush immediately.
       
   218      */
       
   219     public void flushNow(int position) {
       
   220         buf.position(position);
       
   221         flushNow();
       
   222     }
       
   223 }