Bug 80 - redraw after reshape, swapBuffer() gives Exception
Summary: redraw after reshape, swapBuffer() gives Exception
Status: VERIFIED DUPLICATE of bug 78
Alias: None
Product: Jogl
Classification: JogAmp
Component: core (show other bugs)
Version: 1
Hardware: All windows
: P3 normal
Assignee: Sven Gothel
URL:
Depends on:
Blocks:
 
Reported: 2004-04-30 02:40 CEST by Sven Gothel
Modified: 2010-03-24 07:46 CET (History)
0 users

See Also:
Type: DEFECT
SCM Refs:
Workaround: ---


Attachments
Modified Lesson03.java to show redraw and swapBuffers() problem (11.69 KB, text/plain)
2004-04-30 02:41 CEST, Sven Gothel
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Sven Gothel 2010-03-24 07:46:32 CET


---- Reported by andreas_k 2004-04-30 02:40:10 ----

Issue in forum:

http://www.JavaGaming.org/cgi-bin/JGNetForums/YaBB.cgi?
board=jogl;action=display;num=1083234418

I've found out that the redraw problem after resizing the frame only appears:

- if you make the frame size greater
- if hardware acceleration mode is used

I modified the DefaultCapabilitiesChooser NOT to use the windowsPreferedMode, 
because it doesn't select a Hardware Accelerated mode...

I modified the NeHe Lesson03 code to reproduce the problems:

- swapBuffer() in display function throws Exception but works
- resizing the frame sometimes gives a grey background

Here is the code

/*
 * Lesson03.java
 *
 * Created on July 14, 2003, 12:35 PM
 */

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

import net.java.games.jogl.*;

/** Port of the NeHe OpenGL Tutorial (Lesson 3: Colors)
 * to Java using the Jogl interface to OpenGL.  Jogl can be obtained
 * at http://jogl.dev.java.net/
 *
 * @author Kevin Duling (jattier@hotmail.com)
 */
public class Lesson03
{
  static class Renderer
    implements GLEventListener,
               KeyListener
  {
    /** Called by the drawable to initiate OpenGL rendering by the client.
     * After all GLEventListeners have been notified of a display event, the 
     * drawable will swap its buffers if necessary.
     * @param gLDrawable The GLDrawable object.
     */    
    public void display(GLDrawable gLDrawable)
    {
      final GL gl = gLDrawable.getGL();
      gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
      gl.glLoadIdentity();
      gl.glTranslatef(-1.5f, 0.0f, -6.0f);
      gl.glBegin(GL.GL_TRIANGLES);		    // Drawing Using Triangles
        gl.glColor3f(1.0f, 0.0f, 0.0f);   // Set the current drawing color to 
red
        gl.glVertex3f( 0.0f, 1.0f, 0.0f);	// Top
        gl.glColor3f(0.0f, 1.0f, 0.0f);   // Set the current drawing color to 
green
        gl.glVertex3f(-1.0f,-1.0f, 0.0f);	// Bottom Left
        gl.glColor3f(0.0f, 0.0f, 1.0f);   // Set the current drawing color to 
blue
        gl.glVertex3f( 1.0f,-1.0f, 0.0f);	// Bottom Right
      gl.glEnd();				// Finished Drawing The Triangle
      gl.glTranslatef(3.0f, 0.0f, 0.0f);
      gl.glBegin(GL.GL_QUADS);           	// Draw A Quad
        gl.glColor3f(0.5f, 0.5f, 1.0f);   // Set the current drawing color to 
light blue
        gl.glVertex3f(-1.0f, 1.0f, 0.0f);	// Top Left
        gl.glVertex3f( 1.0f, 1.0f, 0.0f);	// Top Right
        gl.glVertex3f( 1.0f,-1.0f, 0.0f);	// Bottom Right
        gl.glVertex3f(-1.0f,-1.0f, 0.0f);	// Bottom Left
      gl.glEnd();				// Done Drawing The Quad
      gl.glFlush();
      
      gLDrawable.swapBuffers();
    }
    
    
	 /** Called when the display mode has been changed.  <B>!! CURRENTLY 
UNIMPLEMENTED IN JOGL !!</B>
    * @param gLDrawable The GLDrawable object.
    * @param modeChanged Indicates if the video mode has changed.
    * @param deviceChanged Indicates if the video device has changed.
    */
	 public void displayChanged(GLDrawable gLDrawable, boolean modeChanged, 
boolean deviceChanged)
    {
    }
    
	 /** Called by the drawable immediately after the OpenGL context is 
    * initialized for the first time. Can be used to perform one-time OpenGL 
    * initialization such as setup of lights and display lists.
    * @param gLDrawable The GLDrawable object.
    */
   public void init(GLDrawable gLDrawable)
    {
      final GL gl = gLDrawable.getGL();
      gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
      gl.glShadeModel(GL.GL_SMOOTH); // try setting this to GL_FLAT and see 
what happens.
      gLDrawable.addKeyListener(this);
    }
    
  
	 /** Called by the drawable during the first repaint after the 
component has 
    * been resized. The client can update the viewport and view volume of the 
    * window appropriately, for example by a call to 
    * GL.glViewport(int, int, int, int); note that for convenience the component
    * has already called GL.glViewport(int, int, int, int)(x, y, width, height)
    * when this method is called, so the client may not have to do anything in
    * this method.
    * @param gLDrawable The GLDrawable object.
    * @param x The X Coordinate of the viewport rectangle.
    * @param y The Y coordinate of the viewport rectanble.
    * @param width The new width of the window.
    * @param height The new height of the window.
    */
	 public void reshape(GLDrawable gLDrawable, int x, int y, int width, 
int height)
    {
      final GL gl = gLDrawable.getGL();
      final GLU glu = gLDrawable.getGLU();

      if (height <= 0) // avoid a divide by zero error!
        height = 1;
      final float h = (float)width / (float)height;
      gl.glViewport(0, 0, width, height);
      gl.glMatrixMode(GL.GL_PROJECTION);
      gl.glLoadIdentity();
      glu.gluPerspective(45.0f, h, 1.0, 20.0);
      gl.glMatrixMode(GL.GL_MODELVIEW);
      gl.glLoadIdentity();
    }

    /** Invoked when a key has been pressed.
     * See the class description for {@link KeyEvent} for a definition of
     * a key pressed event.
     * @param e The KeyEvent.
     */
    public void keyPressed(KeyEvent e)
    {
      if (e.getKeyCode() == KeyEvent.VK_ESCAPE)
        System.exit(0);
    }
    
    /** Invoked when a key has been released.
     * See the class description for {@link KeyEvent} for a definition of
     * a key released event.
     * @param e The KeyEvent.
     */
    public void keyReleased(KeyEvent e) {}
    
    /** Invoked when a key has been typed.
     * See the class description for {@link KeyEvent} for a definition of
     * a key typed event.
     * @param e The KeyEvent.
     */
    public void keyTyped(KeyEvent e) {}
  }
/**
  * CapsChosser is the 'old' Default chooser of jogl, because
  * on my system the Windows prefered mode is not Hardware accelerated....
  */
  
static class CapsChooser implements GLCapabilitiesChooser {
  public CapsChooser() {
  }
  private static final boolean DEBUG = false;

  public int chooseCapabilities(GLCapabilities desired,
                                GLCapabilities[] available) {
    return chooseCapabilities(desired, available, -1);
  }

  public int chooseCapabilities(GLCapabilities desired,
                                GLCapabilities[] available,
                                int windowSystemRecommendedChoice) {

    if (DEBUG) {
      for (int i = 0; i < available.length; i++) {
        System.err.println("Available " + i + ": " + available[i]);
      }
    }

    /*
    if (windowSystemRecommendedChoice >= 0 &&
        windowSystemRecommendedChoice < available.length &&
        available[windowSystemRecommendedChoice] != null) {
      if (DEBUG) {
        System.err.println("Choosing window system's recommended choice of " + 
windowSystemRecommendedChoice);
        System.err.println(available[windowSystemRecommendedChoice]);
      }
      return windowSystemRecommendedChoice;
    }
    */
    // Create score array
    int[] scores = new int[available.length];
    int NO_SCORE = -9999999;
    int DOUBLE_BUFFER_MISMATCH_PENALTY = 1000;
    int STENCIL_MISMATCH_PENALTY = 500;
    // Pseudo attempt to keep equal rank penalties scale-equivalent
    // (e.g., stencil mismatch is 3 * accum because there are 3 accum
    // components)
    int COLOR_MISMATCH_PENALTY_SCALE     = 36;
    int DEPTH_MISMATCH_PENALTY_SCALE     = 6;
    int ACCUM_MISMATCH_PENALTY_SCALE     = 1;
    int STENCIL_MISMATCH_PENALTY_SCALE   = 3;
    for (int i = 0; i < scores.length; i++) {
      scores[i] = NO_SCORE;
    }
    // Compute score for each
    for (int i = 0; i < scores.length; i++) {
      GLCapabilities cur = available[i];
      if (cur == null) {
        continue;
      }
      if (desired.getStereo() != cur.getStereo()) {
        continue;
      }
      int score = 0;
      // Compute difference in color depth
      // (Note that this decides the direction of all other penalties)
      score += (COLOR_MISMATCH_PENALTY_SCALE *
                ((cur.getRedBits() + cur.getGreenBits() + cur.getBlueBits() + 
cur.getAlphaBits()) -
                 (desired.getRedBits() + desired.getGreenBits() + 
desired.getBlueBits() + desired.getAlphaBits())));
      // Compute difference in depth buffer depth
      score += (DEPTH_MISMATCH_PENALTY_SCALE * sign(score) *
                Math.abs(cur.getDepthBits() - desired.getDepthBits()));
      // Compute difference in accumulation buffer depth
      score += (ACCUM_MISMATCH_PENALTY_SCALE * sign(score) *
                Math.abs((cur.getAccumRedBits() + cur.getAccumGreenBits() + 
cur.getAccumBlueBits() + cur.getAccumAlphaBits()) -
                         (desired.getAccumRedBits() + desired.getAccumGreenBits
() + desired.getAccumBlueBits() + desired.getAccumAlphaBits())));
      // Compute difference in stencil bits
      score += STENCIL_MISMATCH_PENALTY_SCALE * sign(score) * 
(cur.getStencilBits() - desired.getStencilBits());
      if (cur.getDoubleBuffered() != desired.getDoubleBuffered()) {
        score += sign(score) * DOUBLE_BUFFER_MISMATCH_PENALTY;
      }
      if ((desired.getStencilBits() > 0) && (cur.getStencilBits() == 0)) {
        score += sign(score) * STENCIL_MISMATCH_PENALTY;
      }
      scores[i] = score;
    }
    // Now prefer hardware-accelerated visuals by pushing scores of
    // non-hardware-accelerated visuals out
    boolean gotHW = false;
    int maxAbsoluteHWScore = 0;
    for (int i = 0; i < scores.length; i++) {
      int score = scores[i];
      if (score == NO_SCORE) {
        continue;
      }
      GLCapabilities cur = available[i];
      if (cur.getHardwareAccelerated()) {
        int absScore = Math.abs(score);
        if (!gotHW ||
            (absScore > maxAbsoluteHWScore)) {
          gotHW = true;
          maxAbsoluteHWScore = absScore;
        }
      }
    }
    if (gotHW) {
      for (int i = 0; i < scores.length; i++) {
        int score = scores[i];
        if (score == NO_SCORE) {
          continue;
        }
        GLCapabilities cur = available[i];
        if (!cur.getHardwareAccelerated()) {
          if (score <= 0) {
            score -= maxAbsoluteHWScore;
          } else if (score > 0) {
            score += maxAbsoluteHWScore;
          }
          scores[i] = score;
        }
      }
    }

    if (DEBUG) {
      System.err.print("Scores: [");
      for (int i = 0; i < available.length; i++) {
        if (i > 0) {
          System.err.print(",");
        }
        System.err.print(" " + scores[i]);
      }
      System.err.println(" ]");
    }

    // Ready to select. Choose score closest to 0.
    int scoreClosestToZero = NO_SCORE;
    int chosenIndex = -1;
    for (int i = 0; i < scores.length; i++) {
      int score = scores[i];
      if (score == NO_SCORE) {
        continue;
      }
      // Don't substitute a positive score for a smaller negative score
      if ((scoreClosestToZero == NO_SCORE) ||
          (Math.abs(score) < Math.abs(scoreClosestToZero) &&
           ((sign(scoreClosestToZero) < 0) || (sign(score) > 0)))) {
        scoreClosestToZero = score;
        chosenIndex = i;
      }
    }
    if (chosenIndex < 0) {
      throw new GLException("Unable to select one of the provided 
GLCapabilities");
    }
    if (DEBUG) {
      System.err.println("Chosen index: " + chosenIndex);
      System.err.println("Chosen capabilities:");
      System.err.println(available[chosenIndex]);
    }

    return chosenIndex;
  }

  private static int sign(int score) {
    if (score < 0) {
      return -1;
    }
    return 1;
  }

}

  /** Program's main entry point
   * @param args command line arguments.
   */
  public static void main(String[] args)
  {
    Frame frame = new Frame("Lesson 3: Colors");
    GLCanvas canvas = GLDrawableFactory.getFactory().createGLCanvas(new 
GLCapabilities(), new CapsChooser());
    canvas.addGLEventListener(new Renderer());
    System.out.println("Version of jogl: " + Version.getVersion());
    
    // switch off auto swap
    canvas.setAutoSwapBufferMode(false);
    frame.add(canvas);
//    frame.getContentPane().add(canvas);
    frame.setSize(640, 480);
    frame.addWindowListener(new WindowAdapter()
    {
      public void windowClosing(WindowEvent e)
      {
        System.exit(0);
      }
    });
    frame.show();
    canvas.requestFocus();
  }
}



---- Additional Comments From andreas_k 2004-04-30 02:41:18 ----

Created an attachment
Modified Lesson03.java to show redraw and swapBuffers() problem




---- Additional Comments From kbr 2004-04-30 15:03:21 ----

The context handling and optimization code in GLContext.invokeGL() was buggy. A
restructuring and simplification has fixed this problem. Am waiting for
confirmation that this fix also fixes issue 78. If it does, this issue will be
closed as a duplicate of that one. Thanks for the self-contained test case.




---- Additional Comments From kbr 2004-05-05 23:51:22 ----

Thanks again for the self-contained test case. The submitter of issue 78 has
confirmed that the fix fixes that issue as well so I'm closing this one as a
duplicate of that.


*** This issue has been marked as a duplicate of 78 ***



--- Bug imported by sgothel@jausoft.com 2010-03-24 07:46 EDT  ---

This bug was previously known as _bug_ 80 at https://jogl.dev.java.net/bugs/show_bug.cgi?id=80
Imported an attachment (id=21)

The original submitter of attachment 21 [details] is unknown.
   Reassigning to the person who moved it here: sgothel@jausoft.com.