001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Oleg V. Khaschansky
019: * @version $Revision$
020: */package org.apache.harmony.awt.gl.linux;
021:
022: import org.apache.harmony.awt.nativebridge.linux.X11;
023: import org.apache.harmony.awt.nativebridge.linux.GLX;
024: import org.apache.harmony.awt.gl.opengl.GLDefs;
025: import org.apache.harmony.awt.nativebridge.*;
026: import org.apache.harmony.awt.gl.opengl.OGLContextManager;
027: import org.apache.harmony.awt.gl.opengl.OGLVolatileImage;
028:
029: import java.util.ArrayList;
030: import java.awt.image.VolatileImage;
031:
032: public class GLXGraphicsConfiguration extends XGraphicsConfiguration
033: implements OGLContextManager {
034: private static final GLX glx = GLX.getInstance();
035:
036: private VoidPointer glxFBConfig; // Cached GLX FB configuration
037:
038: private static long currentOGLContext; // Stored to eliminate unneccessary native calls
039: private static long currentDrawable; // Stored to eliminate unneccessary native calls
040: private static ArrayList existingContexts = new ArrayList();
041:
042: //private long oglContext; // Last OGL context created for this configuration
043: private static final ThreadLocal oglContextThreadLocal = new ThreadLocal();
044:
045: private long getLocalOGLContext() {
046: Long ctxId = (Long) oglContextThreadLocal.get();
047: return ctxId == null ? 0 : ctxId.longValue();
048: }
049:
050: public GLXGraphicsConfiguration(XGraphicsDevice dev,
051: X11.XVisualInfo info) {
052: super (dev, info);
053: }
054:
055: static final class GlxConfigsRec { // Represent configs for one dpy/scr combination
056: // Glx configs for all dpy/scr combinations
057: private static final ArrayList glxConfigs = new ArrayList(1);
058:
059: private PointerPointer configs;
060: private int nConfigs;
061: private long display;
062: private int screen;
063:
064: private static final GlxConfigsRec findConfigRec(long display,
065: int screen) {
066: for (int i = 0; i < glxConfigs.size(); i++) {
067: GlxConfigsRec rec = (GlxConfigsRec) glxConfigs.get(i);
068: if (rec.display == display && rec.screen == screen)
069: return rec;
070: }
071:
072: // Not found
073: return addConfigRec(display, screen);
074: }
075:
076: private static final GlxConfigsRec addConfigRec(long display,
077: int screen) {
078: Int32Pointer nElements = NativeBridge.getInstance()
079: .createInt32Pointer(1, true);
080: Int32Pointer attribList = NativeBridge.getInstance()
081: .createInt32Pointer(9, true);
082:
083: // Fill in FB config attributes
084: attribList.set(0, GLDefs.GLX_DRAWABLE_TYPE);
085: attribList.set(1, GLDefs.GLX_WINDOW_BIT
086: | GLDefs.GLX_PBUFFER_BIT);
087: attribList.set(2, GLDefs.GLX_RENDER_TYPE);
088: attribList.set(3, GLDefs.GLX_RGBA_BIT);
089: attribList.set(4, GLDefs.GLX_STENCIL_SIZE);
090: attribList.set(5, 1);
091: attribList.set(6, GLDefs.GLX_ALPHA_SIZE);
092: attribList.set(7, 8);
093: attribList.set(8, 0);
094:
095: GlxConfigsRec res = new GlxConfigsRec();
096: res.configs = glx.glXChooseFBConfig(display, screen,
097: attribList, nElements);
098: res.nConfigs = nElements.get(0);
099: res.display = display;
100: res.screen = screen;
101:
102: nElements.free();
103: attribList.free();
104:
105: glxConfigs.add(res);
106:
107: return res;
108: }
109:
110: static final long getBestGLXVisualId(long display, int screen) {
111: long defVisualPtr = x11.XDefaultVisual(display, screen);
112: long defVisId = x11.XVisualIDFromVisual(defVisualPtr);
113:
114: GlxConfigsRec rec = findConfigRec(display, screen);
115:
116: if (rec.nConfigs <= 0) {
117: return 0; // No GLX configs found
118: }
119:
120: // Check if default visual is ok
121: Int32Pointer visId = NativeBridge.getInstance()
122: .createInt32Pointer(1, true);
123: VoidPointer ptr = rec.configs.get(0);
124: for (int i = 0; i < rec.nConfigs; i++) {
125: Int8Pointer fbConfig = ptr.byteBase.getElementPointer(i
126: * NativeBridge.ptrSize);
127: glx.glXGetFBConfigAttrib(display, fbConfig.lock(),
128: GLDefs.GLX_VISUAL_ID, visId);
129: fbConfig.unlock();
130: if (visId.get(0) == defVisId) {
131: visId.free();
132: return defVisId;
133: }
134: }
135:
136: // Get visual id from the first (best) FB config
137: VoidPointer fbConfig = rec.configs.get(0);
138: glx.glXGetFBConfigAttrib(display, fbConfig.lock(),
139: GLDefs.GLX_VISUAL_ID, visId);
140: fbConfig.unlock();
141: long bestVisId = visId.get(0);
142: visId.free();
143:
144: return bestVisId;
145: }
146:
147: private static final VoidPointer getGLXFBConfig(long display,
148: int screen, long visid) {
149: VoidPointer retval = null;
150: GlxConfigsRec rec = findConfigRec(display, screen);
151:
152: Int32Pointer visId = NativeBridge.getInstance()
153: .createInt32Pointer(1, true);
154: VoidPointer ptr = rec.configs.get(0);
155: for (int i = 0; i < rec.nConfigs; i++) {
156: Int8Pointer fbConfig = ptr.byteBase.getElementPointer(i
157: * NativeBridge.ptrSize);
158: glx.glXGetFBConfigAttrib(display, fbConfig.lock(),
159: GLDefs.GLX_VISUAL_ID, visId);
160: fbConfig.unlock();
161: if (visId.get(0) == visid) {
162: retval = fbConfig;
163: break;
164: }
165: }
166: visId.free();
167:
168: return retval;
169: }
170:
171: protected void finalize() throws Throwable {
172: super .finalize();
173: if (configs != null)
174: x11.XFree(configs);
175: }
176: }
177:
178: public final long getOGLContext(long drawable, long hdc) {
179: if (glxFBConfig == null) {
180: glxFBConfig = GlxConfigsRec.getGLXFBConfig(dev.display,
181: dev.screen, info.get_visualid());
182: }
183:
184: long oglContext = getLocalOGLContext();
185: if (oglContext == 0) {
186: oglContext = glx.glXCreateNewContext(dev.display,
187: glxFBConfig.lock(), GLDefs.GLX_RGBA_TYPE,
188: existingContexts.isEmpty() ? 0
189: : ((Long) existingContexts.get(0))
190: .longValue(), GLDefs.True);
191: glxFBConfig.unlock();
192:
193: existingContexts.add(new Long(oglContext));
194:
195: oglContextThreadLocal.set(new Long(oglContext));
196: }
197:
198: return oglContext;
199: }
200:
201: protected void finalize() throws Throwable {
202: super .finalize();
203:
204: long oglContext = getLocalOGLContext();
205: if (oglContext != 0) {
206: destroyOGLContext(oglContext);
207: //oglContext = 0;
208: oglContextThreadLocal.set(null);
209:
210: // Remove from the common list of contexts
211: existingContexts.remove(new Long(oglContext));
212: }
213:
214: OffscreenBufferObject.clearCache();
215: }
216:
217: public final void destroyOGLContext(long oglContext) {
218: if (oglContext == currentOGLContext) {
219: //gl.glXMakeCurrent(dev.display, 0, 0);
220: currentOGLContext = 0;
221: }
222:
223: glx.glXDestroyContext(dev.display, oglContext);
224: }
225:
226: public final boolean makeCurrent(long oglContext, long drawable,
227: long hdc) {
228: if (oglContext != currentOGLContext
229: || drawable != currentDrawable) {
230:
231: glx.glXMakeCurrent(dev.display, drawable, oglContext);
232:
233: currentOGLContext = oglContext;
234: currentDrawable = drawable;
235:
236: return true;
237: }
238:
239: return false;
240: }
241:
242: public final boolean makeContextCurrent(long oglContext, long draw,
243: long read, long drawHDC, long readHDC) {
244: if (read == draw) {
245: return makeCurrent(oglContext, read, 0);
246: }
247:
248: glx.glXMakeContextCurrent(dev.display, draw, read, oglContext);
249: // Always step into makeCurrent to set same read/draw drawables
250: // after calling this method.
251: currentOGLContext = 0;
252:
253: return true;
254: }
255:
256: public final void swapBuffers(long drawable, long hdc) {
257: glx.glXSwapBuffers(dev.display, drawable);
258: }
259:
260: public final OffscreenBufferObject createOffscreenBuffer(int w,
261: int h) {
262: if (glxFBConfig == null) {
263: glxFBConfig = GlxConfigsRec.getGLXFBConfig(dev.display,
264: dev.screen, info.get_visualid());
265: }
266:
267: // Try to get pbuffer from cache
268: OffscreenBufferObject pbuffer = OffscreenBufferObject
269: .getCachedBuffer(w, h, this );
270: if (pbuffer != null) {
271: return pbuffer;
272: }
273:
274: Int32Pointer attribList = NativeBridge.getInstance()
275: .createInt32Pointer(7, true);
276:
277: // Fill in FB config attributes
278: attribList.set(0, GLDefs.GLX_PBUFFER_WIDTH);
279: attribList.set(1, w);
280: attribList.set(2, GLDefs.GLX_PBUFFER_HEIGHT);
281: attribList.set(3, h);
282: attribList.set(4, GLDefs.GLX_PRESERVED_CONTENTS);
283: attribList.set(5, GLDefs.True);
284: attribList.set(6, 0);
285:
286: long pbufferId = glx.glXCreatePbuffer(dev.display, glxFBConfig
287: .lock(), attribList);
288: attribList.free();
289: glxFBConfig.unlock();
290:
291: return new OffscreenBufferObject(pbufferId, 0, w, h, this );
292: }
293:
294: public void freeOffscreenBuffer(OffscreenBufferObject pbuffer) {
295: pbuffer = OffscreenBufferObject.freeCachedBuffer(pbuffer);
296:
297: if (pbuffer != null) {
298: glx.glXDestroyPbuffer(dev.display, pbuffer.id);
299: }
300: }
301:
302: public void freeOffscreenBuffer(long id, long hdc) {
303: glx.glXDestroyPbuffer(dev.display, id);
304: }
305:
306: public VolatileImage createCompatibleVolatileImage(int width,
307: int height) {
308: return new OGLVolatileImage(this, width, height);
309: }
310: }
|