001: /*
002: * Copyright 2005-2007 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.java2d.opengl;
027:
028: import sun.java2d.pipe.RenderBuffer;
029: import sun.java2d.pipe.RenderQueue;
030: import static sun.java2d.pipe.BufferedOpCodes.*;
031:
032: /**
033: * OGL-specific implementation of RenderQueue. This class provides a
034: * single (daemon) thread that is responsible for periodically flushing
035: * the queue, thus ensuring that only one thread communicates with the native
036: * OpenGL libraries for the entire process.
037: */
038: public class OGLRenderQueue extends RenderQueue {
039:
040: private static OGLRenderQueue theInstance;
041: private final QueueFlusher flusher;
042:
043: private OGLRenderQueue() {
044: flusher = new QueueFlusher();
045: }
046:
047: /**
048: * Returns the single OGLRenderQueue instance. If it has not yet been
049: * initialized, this method will first construct the single instance
050: * before returning it.
051: */
052: public static synchronized OGLRenderQueue getInstance() {
053: if (theInstance == null) {
054: theInstance = new OGLRenderQueue();
055: }
056: return theInstance;
057: }
058:
059: /**
060: * Flushes the single OGLRenderQueue instance synchronously. If an
061: * OGLRenderQueue has not yet been instantiated, this method is a no-op.
062: * This method is useful in the case of Toolkit.sync(), in which we want
063: * to flush the OGL pipeline, but only if the OGL pipeline is currently
064: * enabled. Since this class has few external dependencies, callers need
065: * not be concerned that calling this method will trigger initialization
066: * of the OGL pipeline and related classes.
067: */
068: public static void sync() {
069: if (theInstance != null) {
070: theInstance.lock();
071: try {
072: theInstance.ensureCapacity(4);
073: theInstance.getBuffer().putInt(SYNC);
074: theInstance.flushNow();
075: } finally {
076: theInstance.unlock();
077: }
078: }
079: }
080:
081: /**
082: * Disposes the native memory associated with the given native
083: * graphics config info pointer on the single queue flushing thread.
084: */
085: public static void disposeGraphicsConfig(long pConfigInfo) {
086: OGLRenderQueue rq = getInstance();
087: rq.lock();
088: try {
089: // make sure we make the context associated with the given
090: // GraphicsConfig current before disposing the native resources
091: OGLContext.setScratchSurface(pConfigInfo);
092:
093: RenderBuffer buf = rq.getBuffer();
094: rq.ensureCapacityAndAlignment(12, 4);
095: buf.putInt(DISPOSE_CONFIG);
096: buf.putLong(pConfigInfo);
097:
098: // this call is expected to complete synchronously, so flush now
099: rq.flushNow();
100: } finally {
101: rq.unlock();
102: }
103: }
104:
105: /**
106: * Returns true if the current thread is the OGL QueueFlusher thread.
107: */
108: public static boolean isQueueFlusherThread() {
109: return (Thread.currentThread() == getInstance().flusher);
110: }
111:
112: public void flushNow() {
113: // assert lock.isHeldByCurrentThread();
114: try {
115: flusher.flushNow();
116: } catch (Exception e) {
117: System.err.println("exception in flushNow:");
118: e.printStackTrace();
119: }
120: }
121:
122: public void flushAndInvokeNow(Runnable r) {
123: // assert lock.isHeldByCurrentThread();
124: try {
125: flusher.flushAndInvokeNow(r);
126: } catch (Exception e) {
127: System.err.println("exception in flushAndInvokeNow:");
128: e.printStackTrace();
129: }
130: }
131:
132: private native void flushBuffer(long buf, int limit);
133:
134: private void flushBuffer() {
135: // assert lock.isHeldByCurrentThread();
136: int limit = buf.position();
137: if (limit > 0) {
138: // process the queue
139: flushBuffer(buf.getAddress(), limit);
140: }
141: // reset the buffer position
142: buf.clear();
143: // clear the set of references, since we no longer need them
144: refSet.clear();
145: }
146:
147: private class QueueFlusher extends Thread {
148: private boolean needsFlush;
149: private Runnable task;
150: private Error error;
151:
152: public QueueFlusher() {
153: super ("Java2D Queue Flusher");
154: setDaemon(true);
155: setPriority(Thread.MAX_PRIORITY);
156: start();
157: }
158:
159: public synchronized void flushNow() {
160: // wake up the flusher
161: needsFlush = true;
162: notify();
163:
164: // wait for flush to complete
165: while (needsFlush) {
166: try {
167: wait();
168: } catch (InterruptedException e) {
169: }
170: }
171:
172: // re-throw any error that may have occurred during the flush
173: if (error != null) {
174: throw error;
175: }
176: }
177:
178: public synchronized void flushAndInvokeNow(Runnable task) {
179: this .task = task;
180: flushNow();
181: }
182:
183: public synchronized void run() {
184: boolean timedOut = false;
185: while (true) {
186: while (!needsFlush) {
187: try {
188: timedOut = false;
189: /*
190: * Wait until we're woken up with a flushNow() call,
191: * or the timeout period elapses (so that we can
192: * flush the queue periodically).
193: */
194: wait(100);
195: /*
196: * We will automatically flush the queue if the
197: * following conditions apply:
198: * - the wait() timed out
199: * - we can lock the queue (without blocking)
200: * - there is something in the queue to flush
201: * Otherwise, just continue (we'll flush eventually).
202: */
203: if (!needsFlush && (timedOut = tryLock())) {
204: if (buf.position() > 0) {
205: needsFlush = true;
206: } else {
207: unlock();
208: }
209: }
210: } catch (InterruptedException e) {
211: }
212: }
213: try {
214: // reset the throwable state
215: error = null;
216: // flush the buffer now
217: flushBuffer();
218: // if there's a task, invoke that now as well
219: if (task != null) {
220: task.run();
221: }
222: } catch (Error e) {
223: error = e;
224: } catch (Exception x) {
225: System.err.println("exception in QueueFlusher:");
226: x.printStackTrace();
227: } finally {
228: if (timedOut) {
229: unlock();
230: }
231: task = null;
232: // allow the waiting thread to continue
233: needsFlush = false;
234: notify();
235: }
236: }
237: }
238: }
239: }
|