summaryrefslogtreecommitdiffstats
path: root/src/net
diff options
context:
space:
mode:
Diffstat (limited to 'src/net')
-rw-r--r--src/net/java/games/jogl/DefaultGLCapabilitiesChooser.java4
-rw-r--r--src/net/java/games/jogl/GLJPanel.java539
-rw-r--r--src/net/java/games/jogl/GLPbuffer.java5
-rwxr-xr-xsrc/net/java/games/jogl/impl/Debug.java87
-rw-r--r--src/net/java/games/jogl/impl/FunctionAvailabilityCache.java2
-rw-r--r--src/net/java/games/jogl/impl/GLContext.java2
-rw-r--r--src/net/java/games/jogl/impl/GLPbufferImpl.java4
-rwxr-xr-xsrc/net/java/games/jogl/impl/SingleThreadedWorkaround.java4
-rw-r--r--src/net/java/games/jogl/impl/macosx/MacOSXPbufferGLContext.java7
-rw-r--r--src/net/java/games/jogl/impl/windows/WindowsOffscreenGLContext.java3
-rw-r--r--src/net/java/games/jogl/impl/windows/WindowsPbufferGLContext.java24
-rw-r--r--src/net/java/games/jogl/impl/x11/X11GLContext.java12
-rw-r--r--src/net/java/games/jogl/impl/x11/X11PbufferGLContext.java26
13 files changed, 563 insertions, 156 deletions
diff --git a/src/net/java/games/jogl/DefaultGLCapabilitiesChooser.java b/src/net/java/games/jogl/DefaultGLCapabilitiesChooser.java
index 8d5ecabc9..01e15f1fa 100644
--- a/src/net/java/games/jogl/DefaultGLCapabilitiesChooser.java
+++ b/src/net/java/games/jogl/DefaultGLCapabilitiesChooser.java
@@ -39,6 +39,8 @@
package net.java.games.jogl;
+import net.java.games.jogl.impl.Debug;
+
/** <P> The default implementation of the {@link
GLCapabilitiesChooser} interface, which provides consistent visual
selection behavior across platforms. The precise algorithm is
@@ -78,7 +80,7 @@ package net.java.games.jogl;
*/
public class DefaultGLCapabilitiesChooser implements GLCapabilitiesChooser {
- private static final boolean DEBUG = false;
+ private static final boolean DEBUG = Debug.debug("DefaultGLCapabilitiesChooser");
public int chooseCapabilities(GLCapabilities desired,
GLCapabilities[] available,
diff --git a/src/net/java/games/jogl/GLJPanel.java b/src/net/java/games/jogl/GLJPanel.java
index 9ebec3079..b22f91b58 100644
--- a/src/net/java/games/jogl/GLJPanel.java
+++ b/src/net/java/games/jogl/GLJPanel.java
@@ -40,6 +40,8 @@
package net.java.games.jogl;
import java.awt.Component;
+import java.awt.EventQueue;
+import java.awt.Frame;
import java.awt.Graphics;
import java.awt.GraphicsConfiguration;
import java.awt.Rectangle;
@@ -57,24 +59,43 @@ import net.java.games.jogl.impl.*;
/** A lightweight Swing component which provides OpenGL rendering
support. Provided for compatibility with Swing user interfaces
when adding a heavyweight doesn't work either because of
- Z-ordering or LayoutManager problems. Currently implemented using
- offscreen (i.e., non-hardware accelerated) rendering, so
- performance will likely be poor. This class can not be
+ Z-ordering or LayoutManager problems. This component attempts to
+ use hardware-accelerated rendering via pbuffers and falls back on
+ to software rendering if problems occur. This class can not be
instantiated directly; use {@link GLDrawableFactory} to construct
them. */
public final class GLJPanel extends JPanel implements GLDrawable {
private GLDrawableHelper drawableHelper = new GLDrawableHelper();
- private GLContext context;
- private BufferedImage offscreenImage;
- private int awtFormat;
- private int glFormat;
- private int glType;
- private int glComps;
+
+ // Data used for either pbuffers or pixmap-based offscreen surfaces
+ private GLCapabilities offscreenCaps;
+ private GLCapabilitiesChooser chooser;
+ private GLDrawable shareWith;
+ private BufferedImage offscreenImage;
+ private int neededOffscreenImageWidth;
+ private int neededOffscreenImageHeight;
private DataBufferByte dbByte;
private DataBufferInt dbInt;
private Object semaphore = new Object();
- private boolean repaintDone;
+ private int panelWidth = 0;
+ private int panelHeight = 0;
+ private Updater updater;
+ private int awtFormat;
+ private int glFormat;
+ private int glType;
+
+ // Implementation using pbuffers
+ private static boolean hardwareAccelerationDisabled = true;
+ private boolean pbufferInitializationCompleted;
+ private GLPbuffer pbuffer;
+ private int pbufferWidth = 256;
+ private int pbufferHeight = 256;
+ private GLCanvas heavyweight;
+ private Frame toplevel;
+
+ // Implementation using software rendering
+ private GLContext offscreenContext;
// For saving/restoring of OpenGL state during ReadPixels
private int[] swapbytes = new int[1];
@@ -86,35 +107,76 @@ public final class GLJPanel extends JPanel implements GLDrawable {
GLJPanel(GLCapabilities capabilities, GLCapabilitiesChooser chooser, GLDrawable shareWith) {
super();
+
// Works around problems on many vendors' cards; we don't need a
// back buffer for the offscreen surface anyway
- GLCapabilities myCaps = (GLCapabilities) capabilities.clone();
- myCaps.setDoubleBuffered(false);
- context = GLContextFactory.getFactory().createGLContext(null, myCaps, chooser,
- GLContextHelper.getContext(shareWith));
+ offscreenCaps = (GLCapabilities) capabilities.clone();
+ offscreenCaps.setDoubleBuffered(false);
+ this.chooser = chooser;
+ this.shareWith = shareWith;
+
+ initialize();
}
public void display() {
- // Multithreaded redrawing of Swing components is not allowed
- try {
- synchronized(semaphore) {
- repaintDone = false;
- repaint();
- while (!repaintDone) {
- semaphore.wait();
+ if (EventQueue.isDispatchThread()) {
+ // Can't block this thread
+ repaint();
+ } else {
+ // Multithreaded redrawing of Swing components is not allowed,
+ // so do everything on the event dispatch thread
+ try {
+ // Wait a reasonable period of time for the repaint to
+ // complete, so that we don't swamp the AWT event queue thread
+ // with repaint requests. We used to have an explicit flag to
+ // detect when the repaint completed; unfortunately, under
+ // some circumstances, the top-level window can be torn down
+ // while we're waiting for the repaint to complete, which will
+ // never happen. It doesn't look like there's enough
+ // information in the EventQueue to figure out whether there
+ // are pending events without posting to the queue, which we
+ // don't want to do during shutdown, and adding a
+ // HierarchyListener and watching for displayability events
+ // might be fragile since we don't know exactly how this
+ // component will be used in users' applications. For these
+ // reasons we simply wait up to a brief period of time for the
+ // repaint to complete.
+ synchronized(semaphore) {
+ repaint();
+ semaphore.wait(100);
}
+ } catch (InterruptedException e) {
}
- } catch (InterruptedException e) {
}
}
- /** Overridden from JComponent; calls {@link #display}. Should not
- be invoked by applications directly. */
+ /** Overridden from JComponent; calls {@link
+ GLEventListener#display}. Should not be invoked by applications
+ directly. */
public void paintComponent(Graphics g) {
- displayAction.setGraphics(g);
- context.invokeGL(displayAction, false, initAction);
+ updater.setGraphics(g);
+ if (!hardwareAccelerationDisabled) {
+ if (!pbufferInitializationCompleted) {
+ try {
+ heavyweight.display();
+ pbuffer.display();
+ } catch (GLException e) {
+ // We consider any exception thrown during updating of the
+ // heavyweight or pbuffer during the initialization phases
+ // to be an indication that there was a problem
+ // instantiating the pbuffer, regardless of whether the
+ // exception originated in the user's GLEventListener. In
+ // these cases we immediately back off and use software
+ // rendering.
+ disableHardwareRendering();
+ }
+ } else {
+ pbuffer.display();
+ }
+ } else {
+ offscreenContext.invokeGL(displayAction, false, initAction);
+ }
synchronized(semaphore) {
- repaintDone = true;
semaphore.notifyAll();
}
}
@@ -125,23 +187,57 @@ public final class GLJPanel extends JPanel implements GLDrawable {
directly. */
public void reshape(int x, int y, int width, int height) {
super.reshape(x, y, width, height);
- // NOTE: we don't pay attention to the x and y provided since we
- // are blitting into this component directly
+
+ GLContext context = null;
+ neededOffscreenImageWidth = 0;
+ neededOffscreenImageHeight = 0;
+
+ if (!hardwareAccelerationDisabled) {
+ if (width > pbufferWidth || height > pbufferHeight) {
+ // Must destroy and recreate pbuffer to fit
+ pbuffer.destroy();
+ if (width > pbufferWidth) {
+ pbufferWidth = getNextPowerOf2(width);
+ }
+ if (height > pbufferHeight) {
+ pbufferHeight = getNextPowerOf2(height);
+ }
+ initialize();
+ }
+ GLPbufferImpl pbufferImpl = (GLPbufferImpl) pbuffer;
+ context = pbufferImpl.getContext();
+ // It looks like NVidia's drivers (at least the ones on my
+ // notebook) are buggy and don't allow a rectangle of less than
+ // the pbuffer's width to be read...this doesn't really matter
+ // because it's the Graphics.drawImage() calls that are the
+ // bottleneck. Should probably make the size of the offscreen
+ // image be the exact size of the pbuffer to save some work on
+ // resize operations...
+ neededOffscreenImageWidth = pbufferWidth;
+ neededOffscreenImageHeight = height;
+ } else {
+ offscreenContext.resizeOffscreenContext(width, height);
+ context = offscreenContext;
+ neededOffscreenImageWidth = width;
+ neededOffscreenImageHeight = height;
+ }
+
+ if (offscreenImage != null &&
+ (offscreenImage.getWidth() != neededOffscreenImageWidth ||
+ offscreenImage.getHeight() != neededOffscreenImageHeight)) {
+ offscreenImage.flush();
+ offscreenImage = null;
+ }
+
+ panelWidth = width;
+ panelHeight = height;
final int fx = 0;
final int fy = 0;
- final int fwidth = width;
- final int fheight = height;
- context.resizeOffscreenContext(width, height);
+
context.invokeGL(new Runnable() {
public void run() {
- getGL().glViewport(fx, fy, fwidth, fheight);
- drawableHelper.reshape(GLJPanel.this, fx, fy, fwidth, fheight);
- if (offscreenImage != null &&
- (offscreenImage.getWidth() != context.getOffscreenContextWidth() ||
- offscreenImage.getHeight() != context.getOffscreenContextHeight())) {
- offscreenImage.flush();
- offscreenImage = null;
- }
+ getGL().glViewport(fx, fy, panelWidth, panelHeight);
+ drawableHelper.reshape(GLJPanel.this, fx, fy, panelWidth, panelHeight);
}
}, true, initAction);
}
@@ -155,19 +251,35 @@ public final class GLJPanel extends JPanel implements GLDrawable {
}
public GL getGL() {
- return context.getGL();
+ if (!hardwareAccelerationDisabled) {
+ return pbuffer.getGL();
+ } else {
+ return offscreenContext.getGL();
+ }
}
public void setGL(GL gl) {
- context.setGL(gl);
+ if (!hardwareAccelerationDisabled) {
+ pbuffer.setGL(gl);
+ } else {
+ offscreenContext.setGL(gl);
+ }
}
public GLU getGLU() {
- return context.getGLU();
+ if (!hardwareAccelerationDisabled) {
+ return pbuffer.getGLU();
+ } else {
+ return offscreenContext.getGLU();
+ }
}
public void setGLU(GLU glu) {
- context.setGLU(glu);
+ if (!hardwareAccelerationDisabled) {
+ pbuffer.setGLU(glu);
+ } else {
+ offscreenContext.setGLU(glu);
+ }
}
public void setRenderingThread(Thread currentThreadOrNull) throws GLException {
@@ -176,7 +288,7 @@ public final class GLJPanel extends JPanel implements GLDrawable {
}
public Thread getRenderingThread() {
- return context.getRenderingThread();
+ return null;
}
public void setNoAutoRedrawMode(boolean noAutoRedraws) {
@@ -187,21 +299,32 @@ public final class GLJPanel extends JPanel implements GLDrawable {
}
public void setAutoSwapBufferMode(boolean onOrOff) {
- context.setAutoSwapBufferMode(onOrOff);
+ if (!hardwareAccelerationDisabled) {
+ pbuffer.setAutoSwapBufferMode(onOrOff);
+ } else {
+ offscreenContext.setAutoSwapBufferMode(onOrOff);
+ }
}
public boolean getAutoSwapBufferMode() {
- return context.getAutoSwapBufferMode();
+ if (!hardwareAccelerationDisabled) {
+ return pbuffer.getAutoSwapBufferMode();
+ } else {
+ return offscreenContext.getAutoSwapBufferMode();
+ }
}
public void swapBuffers() {
- context.invokeGL(swapBuffersAction, false, initAction);
+ if (!hardwareAccelerationDisabled) {
+ pbuffer.swapBuffers();
+ } else {
+ offscreenContext.invokeGL(swapBuffersAction, false, initAction);
+ }
}
public boolean canCreateOffscreenDrawable() {
- // For now let's say no; maybe we can reimplement this class in
- // terms of pbuffers (though not all vendors support them, and
- // they seem to require an onscreen context)
+ // For now let's say no, although we could using the heavyweight
+ // if hardware acceleration is still enabled
return false;
}
@@ -212,119 +335,267 @@ public final class GLJPanel extends JPanel implements GLDrawable {
}
GLContext getContext() {
- return context;
+ if (!hardwareAccelerationDisabled) {
+ return ((GLPbufferImpl) pbuffer).getContext();
+ } else {
+ return offscreenContext;
+ }
}
//----------------------------------------------------------------------
// Internals only below this point
//
- class InitAction implements Runnable {
- public void run() {
- drawableHelper.init(GLJPanel.this);
+ private void disableHardwareRendering() {
+ if (Debug.verbose()) {
+ System.err.println("GLJPanel: Falling back on software rendering due to pbuffer problems");
}
+ hardwareAccelerationDisabled = true;
+ pbufferInitializationCompleted = false;
+ EventQueue.invokeLater(new Runnable() {
+ public void run() {
+ toplevel.setVisible(false);
+ // Should dispose of this -- not sure about stability on
+ // various cards -- should test (FIXME)
+ // toplevel.dispose();
+ }
+ });
+ initialize();
}
- private InitAction initAction = new InitAction();
-
- class DisplayAction implements Runnable {
+
+ private void initialize() {
+ // Initialize either the hardware-accelerated rendering path or
+ // the lightweight rendering path
+ if (!hardwareAccelerationDisabled) {
+ boolean firstTime = false;
+ if (heavyweight == null) {
+ // Make the heavyweight share with the "shareWith" parameter.
+ // The pbuffer shares textures and display lists with the
+ // heavyweight, so by transitivity the pbuffer will share with
+ // it as well.
+ heavyweight = GLDrawableFactory.getFactory().createGLCanvas(new GLCapabilities(), shareWith);
+ firstTime = true;
+ }
+ if (heavyweight.canCreateOffscreenDrawable()) {
+ if (firstTime) {
+ toplevel = new Frame();
+ toplevel.setUndecorated(true);
+ }
+ pbuffer = heavyweight.createOffscreenDrawable(offscreenCaps, pbufferWidth, pbufferHeight);
+ updater = new Updater();
+ pbuffer.addGLEventListener(updater);
+ pbufferInitializationCompleted = false;
+ if (firstTime) {
+ toplevel.add(heavyweight);
+ toplevel.setSize(0, 0);
+ }
+ EventQueue.invokeLater(new Runnable() {
+ public void run() {
+ try {
+ toplevel.setVisible(true);
+ } catch (GLException e) {
+ disableHardwareRendering();
+ }
+ }
+ });
+ return;
+ } else {
+ // If the heavyweight reports that it can't create an
+ // offscreen drawable (pbuffer), don't try again the next
+ // time, and fall through to the software rendering path
+ hardwareAccelerationDisabled = true;
+ }
+ }
+
+ // Create an offscreen context instead
+ offscreenContext = GLContextFactory.getFactory().createGLContext(null, offscreenCaps, chooser,
+ GLContextHelper.getContext(shareWith));
+ offscreenContext.resizeOffscreenContext(panelWidth, panelHeight);
+ updater = new Updater();
+ if (panelWidth > 0 && panelHeight > 0) {
+ offscreenContext.invokeGL(new Runnable() {
+ public void run() {
+ getGL().glViewport(0, 0, panelWidth, panelHeight);
+ drawableHelper.reshape(GLJPanel.this, 0, 0, panelWidth, panelHeight);
+ }
+ }, true, initAction);
+ }
+ }
+
+ class Updater implements GLEventListener {
private Graphics g;
public void setGraphics(Graphics g) {
this.g = g;
}
- public void run() {
+ public void init(GLDrawable drawable) {
+ if (!hardwareAccelerationDisabled) {
+ pbufferInitializationCompleted = true;
+ EventQueue.invokeLater(new Runnable() {
+ public void run() {
+ toplevel.setVisible(false);
+ }
+ });
+ }
+ drawableHelper.init(GLJPanel.this);
+ }
+
+ public void display(GLDrawable drawable) {
drawableHelper.display(GLJPanel.this);
+
// Must now copy pixels from offscreen context into surface
if (offscreenImage == null) {
- int awtFormat = context.getOffscreenContextBufferedImageType();
- offscreenImage = new BufferedImage(context.getOffscreenContextWidth(), context.getOffscreenContextHeight(), awtFormat);
- switch (awtFormat) {
- case BufferedImage.TYPE_3BYTE_BGR:
- glFormat = GL.GL_BGR;
- glType = GL.GL_UNSIGNED_BYTE;
- glComps = 3;
- dbByte = (DataBufferByte) offscreenImage.getRaster().getDataBuffer();
- break;
-
- case BufferedImage.TYPE_INT_RGB:
- glFormat = GL.GL_BGRA;
- glType = GL.GL_UNSIGNED_BYTE;
- glComps = 4;
- dbInt = (DataBufferInt) offscreenImage.getRaster().getDataBuffer();
- break;
-
- case BufferedImage.TYPE_INT_ARGB:
- glFormat = GL.GL_BGRA;
- glType = context.getOffscreenContextPixelDataType();
- glComps = 4;
- dbInt = (DataBufferInt) offscreenImage.getRaster().getDataBuffer();
- break;
-
- default:
- // FIXME: Support more off-screen image types (current
- // offscreen context implementations don't use others, and
- // some of the OpenGL formats aren't supported in the 1.1
- // headers, which we're currently using)
- throw new GLException("Unsupported offscreen image type " + awtFormat);
+ if (panelWidth > 0 && panelHeight > 0) {
+ // It looks like NVidia's drivers (at least the ones on my
+ // notebook) are buggy and don't allow a sub-rectangle to be
+ // read from a pbuffer...this doesn't really matter because
+ // it's the Graphics.drawImage() calls that are the
+ // bottleneck
+
+ int awtFormat = 0;
+ if (!hardwareAccelerationDisabled) {
+ // Should be more flexible in these BufferedImage formats;
+ // perhaps see what the preferred image types are on the
+ // given platform
+ if (offscreenCaps.getAlphaBits() > 0) {
+ awtFormat = BufferedImage.TYPE_INT_ARGB;
+ } else {
+ awtFormat = BufferedImage.TYPE_3BYTE_BGR;
+ }
+ } else {
+ awtFormat = offscreenContext.getOffscreenContextBufferedImageType();
+ }
+
+ offscreenImage = new BufferedImage(neededOffscreenImageWidth,
+ neededOffscreenImageHeight,
+ awtFormat);
+ switch (awtFormat) {
+ case BufferedImage.TYPE_3BYTE_BGR:
+ glFormat = GL.GL_BGR;
+ glType = GL.GL_UNSIGNED_BYTE;
+ dbByte = (DataBufferByte) offscreenImage.getRaster().getDataBuffer();
+ break;
+
+ case BufferedImage.TYPE_INT_RGB:
+ glFormat = GL.GL_BGRA;
+ glType = GL.GL_UNSIGNED_BYTE;
+ dbInt = (DataBufferInt) offscreenImage.getRaster().getDataBuffer();
+ break;
+
+ case BufferedImage.TYPE_INT_ARGB:
+ glFormat = GL.GL_BGRA;
+ glType = (hardwareAccelerationDisabled
+ ? offscreenContext.getOffscreenContextPixelDataType()
+ : GL.GL_UNSIGNED_BYTE);
+ dbInt = (DataBufferInt) offscreenImage.getRaster().getDataBuffer();
+ break;
+
+ default:
+ // FIXME: Support more off-screen image types (current
+ // offscreen context implementations don't use others, and
+ // some of the OpenGL formats aren't supported in the 1.1
+ // headers, which we're currently using)
+ throw new GLException("Unsupported offscreen image type " + awtFormat);
+ }
}
}
- GL gl = getGL();
- // Save current modes
- gl.glGetIntegerv(GL.GL_PACK_SWAP_BYTES, swapbytes);
- gl.glGetIntegerv(GL.GL_PACK_LSB_FIRST, lsbfirst);
- gl.glGetIntegerv(GL.GL_PACK_ROW_LENGTH, rowlength);
- gl.glGetIntegerv(GL.GL_PACK_SKIP_ROWS, skiprows);
- gl.glGetIntegerv(GL.GL_PACK_SKIP_PIXELS, skippixels);
- gl.glGetIntegerv(GL.GL_PACK_ALIGNMENT, alignment);
-
- // Little endian machines (DEC Alpha, Intel X86, PPC (in LSB
- // mode)... for example) could benefit from setting
- // GL_PACK_LSB_FIRST to GL_TRUE instead of GL_FALSE, but this
- // would require changing the generated bitmaps too.
- gl.glPixelStorei(GL.GL_PACK_SWAP_BYTES, GL.GL_FALSE);
- gl.glPixelStorei(GL.GL_PACK_LSB_FIRST, GL.GL_TRUE);
- gl.glPixelStorei(GL.GL_PACK_ROW_LENGTH, offscreenImage.getWidth());
- gl.glPixelStorei(GL.GL_PACK_SKIP_ROWS, 0);
- gl.glPixelStorei(GL.GL_PACK_SKIP_PIXELS, 0);
- gl.glPixelStorei(GL.GL_PACK_ALIGNMENT, 1);
-
- // Actually read the pixels.
- gl.glReadBuffer(context.getOffscreenContextReadBuffer());
- if (dbByte != null) {
- gl.glReadPixels(0, 0, offscreenImage.getWidth(), offscreenImage.getHeight(), glFormat, glType, dbByte.getData());
- } else if (dbInt != null) {
- gl.glReadPixels(0, 0, offscreenImage.getWidth(), offscreenImage.getHeight(), glFormat, glType, dbInt.getData());
- }
+ if (offscreenImage != null) {
+ GL gl = getGL();
+ // Save current modes
+ gl.glGetIntegerv(GL.GL_PACK_SWAP_BYTES, swapbytes);
+ gl.glGetIntegerv(GL.GL_PACK_LSB_FIRST, lsbfirst);
+ gl.glGetIntegerv(GL.GL_PACK_ROW_LENGTH, rowlength);
+ gl.glGetIntegerv(GL.GL_PACK_SKIP_ROWS, skiprows);
+ gl.glGetIntegerv(GL.GL_PACK_SKIP_PIXELS, skippixels);
+ gl.glGetIntegerv(GL.GL_PACK_ALIGNMENT, alignment);
+
+ // Little endian machines (DEC Alpha, Intel X86, PPC (in LSB
+ // mode)... for example) could benefit from setting
+ // GL_PACK_LSB_FIRST to GL_TRUE instead of GL_FALSE, but this
+ // would require changing the generated bitmaps too.
+ gl.glPixelStorei(GL.GL_PACK_SWAP_BYTES, GL.GL_FALSE);
+ gl.glPixelStorei(GL.GL_PACK_LSB_FIRST, GL.GL_TRUE);
+ gl.glPixelStorei(GL.GL_PACK_ROW_LENGTH, offscreenImage.getWidth());
+ gl.glPixelStorei(GL.GL_PACK_SKIP_ROWS, 0);
+ gl.glPixelStorei(GL.GL_PACK_SKIP_PIXELS, 0);
+ gl.glPixelStorei(GL.GL_PACK_ALIGNMENT, 1);
+
+ // Actually read the pixels.
+ gl.glReadBuffer(GL.GL_FRONT);
+ if (dbByte != null) {
+ gl.glReadPixels(0, 0, offscreenImage.getWidth(), offscreenImage.getHeight(), glFormat, glType, dbByte.getData());
+ } else if (dbInt != null) {
+ gl.glReadPixels(0, 0, offscreenImage.getWidth(), offscreenImage.getHeight(), glFormat, glType, dbInt.getData());
+ }
- // Restore saved modes.
- gl.glPixelStorei(GL.GL_PACK_SWAP_BYTES, swapbytes[0]);
- gl.glPixelStorei(GL.GL_PACK_LSB_FIRST, lsbfirst[0]);
- gl.glPixelStorei(GL.GL_PACK_ROW_LENGTH, rowlength[0]);
- gl.glPixelStorei(GL.GL_PACK_SKIP_ROWS, skiprows[0]);
- gl.glPixelStorei(GL.GL_PACK_SKIP_PIXELS, skippixels[0]);
- gl.glPixelStorei(GL.GL_PACK_ALIGNMENT, alignment[0]);
+ // Restore saved modes.
+ gl.glPixelStorei(GL.GL_PACK_SWAP_BYTES, swapbytes[0]);
+ gl.glPixelStorei(GL.GL_PACK_LSB_FIRST, lsbfirst[0]);
+ gl.glPixelStorei(GL.GL_PACK_ROW_LENGTH, rowlength[0]);
+ gl.glPixelStorei(GL.GL_PACK_SKIP_ROWS, skiprows[0]);
+ gl.glPixelStorei(GL.GL_PACK_SKIP_PIXELS, skippixels[0]);
+ gl.glPixelStorei(GL.GL_PACK_ALIGNMENT, alignment[0]);
- gl.glFlush();
- gl.glFinish();
-
- if (context.offscreenImageNeedsVerticalFlip()) {
- g.drawImage(offscreenImage,
- 0, 0, offscreenImage.getWidth(), offscreenImage.getHeight(),
- 0, offscreenImage.getHeight(), offscreenImage.getWidth(), 0,
- GLJPanel.this);
- } else {
- g.drawImage(offscreenImage, 0, 0, offscreenImage.getWidth(), offscreenImage.getHeight(), GLJPanel.this);
+ if (!hardwareAccelerationDisabled ||
+ offscreenContext.offscreenImageNeedsVerticalFlip()) {
+ // This performs reasonably well; the snippet below does not.
+ // Should figure out if we need to set the image scaling
+ // preference to FAST since it doesn't require subsampling
+ // of pixels -- FIXME
+ for (int i = 0; i < panelHeight - 1; i++) {
+ g.drawImage(offscreenImage,
+ 0, i, panelWidth, i+1,
+ 0, panelHeight - i - 2, panelWidth, panelHeight - i - 1,
+ GLJPanel.this);
+ }
+ } else {
+ g.drawImage(offscreenImage, 0, 0, offscreenImage.getWidth(), offscreenImage.getHeight(), GLJPanel.this);
+ }
}
}
+
+ public void reshape(GLDrawable drawable, int x, int y, int width, int height) {
+ // This is handled above and dispatched directly to the appropriate context
+ }
+
+ public void displayChanged(GLDrawable drawable, boolean modeChanged, boolean deviceChanged) {
+ }
+ }
+
+ class InitAction implements Runnable {
+ public void run() {
+ updater.init(GLJPanel.this);
+ }
+ }
+ private InitAction initAction = new InitAction();
+
+ class DisplayAction implements Runnable {
+ public void run() {
+ updater.display(GLJPanel.this);
+ }
}
private DisplayAction displayAction = new DisplayAction();
+ // This one is used exclusively in the non-hardware-accelerated case
class SwapBuffersAction implements Runnable {
public void run() {
- context.swapBuffers();
+ offscreenContext.swapBuffers();
}
}
private SwapBuffersAction swapBuffersAction = new SwapBuffersAction();
+
+ private int getNextPowerOf2(int number) {
+ if (((number-1) & number) == 0) {
+ //ex: 8 -> 0b1000; 8-1=7 -> 0b0111; 0b1000&0b0111 == 0
+ return number;
+ }
+ int power = 0;
+ while (number > 0) {
+ number = number>>1;
+ power++;
+ }
+ return (1<<power);
+ }
}
diff --git a/src/net/java/games/jogl/GLPbuffer.java b/src/net/java/games/jogl/GLPbuffer.java
index d41ca1bd6..fe2c19974 100644
--- a/src/net/java/games/jogl/GLPbuffer.java
+++ b/src/net/java/games/jogl/GLPbuffer.java
@@ -63,4 +63,9 @@ public interface GLPbuffer extends GLDrawable {
/** Queries initialization status of this pBuffer. */
public boolean isInitialized();
+
+ /** Destroys the native resources associated with this pbuffer. It
+ is not valid to call display() or any other routines on this
+ pbuffer after it has been destroyed. */
+ public void destroy();
}
diff --git a/src/net/java/games/jogl/impl/Debug.java b/src/net/java/games/jogl/impl/Debug.java
new file mode 100755
index 000000000..ad0092a6f
--- /dev/null
+++ b/src/net/java/games/jogl/impl/Debug.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2003-2005 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package net.java.games.jogl.impl;
+
+import java.security.*;
+
+/** Helper routines for logging and debugging. */
+
+public class Debug {
+ // Some common properties
+ private static boolean verbose;
+ private static boolean debugAll;
+
+ static {
+ verbose = isPropertyDefined("jogl.verbose");
+ debugAll = isPropertyDefined("jogl.debug");
+ }
+
+ public static boolean getBooleanProperty(final String property) {
+ Boolean b = (Boolean) AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ boolean val = Boolean.getBoolean(property);
+ return (val ? Boolean.TRUE : Boolean.FALSE);
+ }
+ });
+ return b.booleanValue();
+ }
+
+ public static boolean isPropertyDefined(final String property) {
+ Boolean b = (Boolean) AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ String val = System.getProperty(property);
+ return (val != null ? Boolean.TRUE : Boolean.FALSE);
+ }
+ });
+ return b.booleanValue();
+ }
+
+ public static boolean verbose() {
+ return verbose;
+ }
+
+ public static boolean debugAll() {
+ return debugAll;
+ }
+
+ public static boolean debug(String subcomponent) {
+ return debugAll() || isPropertyDefined("jogl.debug." + subcomponent);
+ }
+}
diff --git a/src/net/java/games/jogl/impl/FunctionAvailabilityCache.java b/src/net/java/games/jogl/impl/FunctionAvailabilityCache.java
index bceb66f9b..01a70e4b7 100644
--- a/src/net/java/games/jogl/impl/FunctionAvailabilityCache.java
+++ b/src/net/java/games/jogl/impl/FunctionAvailabilityCache.java
@@ -52,7 +52,7 @@ import java.lang.reflect.*;
* and display.
*/
public final class FunctionAvailabilityCache {
- private static final boolean DEBUG = false;
+ private static final boolean DEBUG = Debug.debug("FunctionAvailabilityCache");
FunctionAvailabilityCache(GLContext context)
{
diff --git a/src/net/java/games/jogl/impl/GLContext.java b/src/net/java/games/jogl/impl/GLContext.java
index cc5d465d6..aab3f9dd0 100644
--- a/src/net/java/games/jogl/impl/GLContext.java
+++ b/src/net/java/games/jogl/impl/GLContext.java
@@ -44,7 +44,7 @@ import net.java.games.jogl.*;
import net.java.games.gluegen.runtime.*;
public abstract class GLContext {
- protected static final boolean DEBUG = false;
+ protected static final boolean DEBUG = Debug.debug("GLContext");
static {
NativeLibLoader.load();
diff --git a/src/net/java/games/jogl/impl/GLPbufferImpl.java b/src/net/java/games/jogl/impl/GLPbufferImpl.java
index 2fb927c92..03d161fdd 100644
--- a/src/net/java/games/jogl/impl/GLPbufferImpl.java
+++ b/src/net/java/games/jogl/impl/GLPbufferImpl.java
@@ -196,6 +196,10 @@ public class GLPbufferImpl implements GLPbuffer {
return isInitialized;
}
+ public void destroy() {
+ context.destroy();
+ }
+
//----------------------------------------------------------------------
// Internals only below this point
//
diff --git a/src/net/java/games/jogl/impl/SingleThreadedWorkaround.java b/src/net/java/games/jogl/impl/SingleThreadedWorkaround.java
index 2ffd09e6a..eb7d8f09d 100755
--- a/src/net/java/games/jogl/impl/SingleThreadedWorkaround.java
+++ b/src/net/java/games/jogl/impl/SingleThreadedWorkaround.java
@@ -52,7 +52,6 @@ public class SingleThreadedWorkaround {
// If the user specified the workaround's system property (either
// true or false), don't let the automatic detection have any effect
private static boolean systemPropertySpecified = false;
- private static boolean verbose = false;
static {
AccessController.doPrivileged(new PrivilegedAction() {
@@ -66,7 +65,6 @@ public class SingleThreadedWorkaround {
systemPropertySpecified = true;
singleThreadedWorkaround = Boolean.valueOf(workaround).booleanValue();
}
- verbose = (System.getProperty("jogl.verbose") != null);
printWorkaroundNotice();
return null;
}
@@ -85,7 +83,7 @@ public class SingleThreadedWorkaround {
}
private static void printWorkaroundNotice() {
- if (singleThreadedWorkaround && verbose) {
+ if (singleThreadedWorkaround && Debug.verbose()) {
System.err.println("Using single-threaded workaround of dispatching display() on event thread");
}
}
diff --git a/src/net/java/games/jogl/impl/macosx/MacOSXPbufferGLContext.java b/src/net/java/games/jogl/impl/macosx/MacOSXPbufferGLContext.java
index 6ac854090..8e65ce1f3 100644
--- a/src/net/java/games/jogl/impl/macosx/MacOSXPbufferGLContext.java
+++ b/src/net/java/games/jogl/impl/macosx/MacOSXPbufferGLContext.java
@@ -4,8 +4,7 @@ import net.java.games.jogl.*;
import net.java.games.jogl.impl.*;
public class MacOSXPbufferGLContext extends MacOSXGLContext {
-
- private static final boolean DEBUG = false;
+ private static final boolean DEBUG = Debug.debug("MacOSXPbufferGLContext");
protected int initWidth;
protected int initHeight;
@@ -131,6 +130,10 @@ public class MacOSXPbufferGLContext extends MacOSXGLContext {
return false;
}
+ protected void destroyImpl() throws GLException {
+ destroyPBuffer();
+ }
+
public void swapBuffers() throws GLException {
// FIXME: do we need to do anything if the pbuffer is double-buffered?
}
diff --git a/src/net/java/games/jogl/impl/windows/WindowsOffscreenGLContext.java b/src/net/java/games/jogl/impl/windows/WindowsOffscreenGLContext.java
index 9e871caba..5743253a0 100644
--- a/src/net/java/games/jogl/impl/windows/WindowsOffscreenGLContext.java
+++ b/src/net/java/games/jogl/impl/windows/WindowsOffscreenGLContext.java
@@ -172,7 +172,8 @@ public class WindowsOffscreenGLContext extends WindowsGLContext {
}
hbitmap = WGL.CreateDIBSection(hdc, info, WGL.DIB_RGB_COLORS, 0, 0, 0);
if (hbitmap == 0) {
- throw new GLException("Error creating offscreen bitmap");
+ throw new GLException("Error creating offscreen bitmap of width " + width +
+ ", height " + height);
}
if ((origbitmap = WGL.SelectObject(hdc, hbitmap)) == 0) {
throw new GLException("Error selecting bitmap into new device context");
diff --git a/src/net/java/games/jogl/impl/windows/WindowsPbufferGLContext.java b/src/net/java/games/jogl/impl/windows/WindowsPbufferGLContext.java
index d3795905f..9d803d58a 100644
--- a/src/net/java/games/jogl/impl/windows/WindowsPbufferGLContext.java
+++ b/src/net/java/games/jogl/impl/windows/WindowsPbufferGLContext.java
@@ -43,7 +43,7 @@ import net.java.games.jogl.*;
import net.java.games.jogl.impl.*;
public class WindowsPbufferGLContext extends WindowsGLContext {
- private static final boolean DEBUG = false;
+ private static final boolean DEBUG = Debug.debug("WindowsPbufferGLContext");
private int initWidth;
private int initHeight;
@@ -308,10 +308,16 @@ public class WindowsPbufferGLContext extends WindowsGLContext {
if (buffer == 0) {
// pbuffer not instantiated yet
+ if (DEBUG) {
+ System.err.println("pbuffer not instantiated yet");
+ }
return false;
}
boolean res = super.makeCurrent(initAction);
+ if (DEBUG) {
+ System.err.println("super.makeCurrent() = " + res + ", created = " + created);
+ }
if (created) {
// Initialize render-to-texture support if requested
rtt = capabilities.getOffscreenRenderToTexture();
@@ -396,6 +402,22 @@ public class WindowsPbufferGLContext extends WindowsGLContext {
}
}
+ protected void destroyImpl() throws GLException {
+ if (hglrc != 0) {
+ super.destroyImpl();
+ // Must release DC and pbuffer
+ GL gl = getGL();
+ if (gl.wglReleasePbufferDCARB(buffer, hdc) == 0) {
+ throw new GLException("Error releasing pbuffer device context: error code " + WGL.GetLastError());
+ }
+ hdc = 0;
+ if (!gl.wglDestroyPbufferARB(buffer)) {
+ throw new GLException("Error destroying pbuffer: error code " + WGL.GetLastError());
+ }
+ buffer = 0;
+ }
+ }
+
public void swapBuffers() throws GLException {
// FIXME: do we need to do anything if the pbuffer is double-buffered?
// For now, just grab the pixels for the render-to-texture support.
diff --git a/src/net/java/games/jogl/impl/x11/X11GLContext.java b/src/net/java/games/jogl/impl/x11/X11GLContext.java
index efcd9a101..1f8023e66 100644
--- a/src/net/java/games/jogl/impl/x11/X11GLContext.java
+++ b/src/net/java/games/jogl/impl/x11/X11GLContext.java
@@ -187,6 +187,7 @@ public abstract class X11GLContext extends GLContext {
}
protected void destroyImpl() throws GLException {
+ lockAWT();
if (context != 0) {
GLX.glXDestroyContext(mostRecentDisplay, context);
if (DEBUG) {
@@ -194,6 +195,7 @@ public abstract class X11GLContext extends GLContext {
}
context = 0;
}
+ unlockAWT();
}
public abstract void swapBuffers() throws GLException;
@@ -381,4 +383,14 @@ public abstract class X11GLContext extends GLContext {
protected long getContext() {
return context;
}
+
+ // These synchronization primitives prevent the AWT from making
+ // requests from the X server asynchronously to this code.
+ protected void lockAWT() {
+ getJAWT().Lock();
+ }
+
+ protected void unlockAWT() {
+ getJAWT().Unlock();
+ }
}
diff --git a/src/net/java/games/jogl/impl/x11/X11PbufferGLContext.java b/src/net/java/games/jogl/impl/x11/X11PbufferGLContext.java
index a253b9615..5b6df1843 100644
--- a/src/net/java/games/jogl/impl/x11/X11PbufferGLContext.java
+++ b/src/net/java/games/jogl/impl/x11/X11PbufferGLContext.java
@@ -43,7 +43,7 @@ import net.java.games.jogl.*;
import net.java.games.jogl.impl.*;
public class X11PbufferGLContext extends X11GLContext {
- private static final boolean DEBUG = false;
+ private static final boolean DEBUG = Debug.debug("X11PbufferGLContext");
private int initWidth;
private int initHeight;
@@ -315,6 +315,19 @@ public class X11PbufferGLContext extends X11GLContext {
}
}
+ protected void destroyImpl() throws GLException {
+ lockAWT();
+ try {
+ if (context != 0) {
+ super.destroyImpl();
+ GLX.glXDestroyPbuffer(display, buffer);
+ buffer = 0;
+ }
+ } finally {
+ unlockAWT();
+ }
+ }
+
public void swapBuffers() throws GLException {
// FIXME: do we need to do anything if the pbuffer is double-buffered?
}
@@ -326,15 +339,4 @@ public class X11PbufferGLContext extends X11GLContext {
}
return tmp[0];
}
-
- // These synchronization primitives, which prevent the AWT from
- // making requests from the X server asynchronously to this code,
- // are required for pbuffers to work properly on X11.
- private void lockAWT() {
- getJAWT().Lock();
- }
-
- private void unlockAWT() {
- getJAWT().Unlock();
- }
}