blob: 00df7dd62e01c395e476f79a38b57599d72dfa41 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2005-2007 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
26package sun.java2d.opengl;
27
28import sun.java2d.pipe.RenderBuffer;
29import sun.java2d.pipe.RenderQueue;
30import static sun.java2d.pipe.BufferedOpCodes.*;
31
32/**
33 * OGL-specific implementation of RenderQueue. This class provides a
34 * single (daemon) thread that is responsible for periodically flushing
35 * the queue, thus ensuring that only one thread communicates with the native
36 * OpenGL libraries for the entire process.
37 */
38public class OGLRenderQueue extends RenderQueue {
39
40 private static OGLRenderQueue theInstance;
41 private final QueueFlusher flusher;
42
43 private OGLRenderQueue() {
44 flusher = new QueueFlusher();
45 }
46
47 /**
48 * Returns the single OGLRenderQueue instance. If it has not yet been
49 * initialized, this method will first construct the single instance
50 * before returning it.
51 */
52 public static synchronized OGLRenderQueue getInstance() {
53 if (theInstance == null) {
54 theInstance = new OGLRenderQueue();
55 }
56 return theInstance;
57 }
58
59 /**
60 * Flushes the single OGLRenderQueue instance synchronously. If an
61 * OGLRenderQueue has not yet been instantiated, this method is a no-op.
62 * This method is useful in the case of Toolkit.sync(), in which we want
63 * to flush the OGL pipeline, but only if the OGL pipeline is currently
64 * enabled. Since this class has few external dependencies, callers need
65 * not be concerned that calling this method will trigger initialization
66 * of the OGL pipeline and related classes.
67 */
68 public static void sync() {
69 if (theInstance != null) {
70 theInstance.lock();
71 try {
72 theInstance.ensureCapacity(4);
73 theInstance.getBuffer().putInt(SYNC);
74 theInstance.flushNow();
75 } finally {
76 theInstance.unlock();
77 }
78 }
79 }
80
81 /**
82 * Disposes the native memory associated with the given native
83 * graphics config info pointer on the single queue flushing thread.
84 */
85 public static void disposeGraphicsConfig(long pConfigInfo) {
86 OGLRenderQueue rq = getInstance();
87 rq.lock();
88 try {
89 // make sure we make the context associated with the given
90 // GraphicsConfig current before disposing the native resources
91 OGLContext.setScratchSurface(pConfigInfo);
92
93 RenderBuffer buf = rq.getBuffer();
94 rq.ensureCapacityAndAlignment(12, 4);
95 buf.putInt(DISPOSE_CONFIG);
96 buf.putLong(pConfigInfo);
97
98 // this call is expected to complete synchronously, so flush now
99 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}