gnustep-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

NSOpenGL


From: Thomas Gamper
Subject: NSOpenGL
Date: Fri, 18 Jan 2008 18:29:46 +0100
User-agent: Thunderbird 2.0.0.6 (X11/20071022)

Hi!

Recently I was using NSOpenGLView and fixed a couple of bugs in gnustep-back 0.12.0 ( I believe newer versions have the same issues):

- XGGLPixelFormat handling was confusing glx parameters, since glx 1.3 has some different parameters than earlier versions of glx - XGGLContext did not create the rendering context, the x window, and the glx window with the same Visual - XGGLContext did not create a colormap for the x window (which has to use the same Visual too)

The attached files fix this issues. I tried to follow the gnustep coding style but I am not sure if I succeeded :)

Please let me know if there are any change requests.
I am not subscribed to the list, so please CC me.

Thanks

TOM
/*      -*-ObjC-*- */
/* XGOpenGL - openGL management using glX

   Copyright (C) 2002 Free Software Foundation, Inc.

   Author: Frederic De Jaeger
   Date: Nov 2002

   This file is part of the GNUstep GUI Library.

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.
   
   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public
   License along with this library; see the file COPYING.LIB.
   If not, write to the Free Software Foundation,
   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/ 

#ifndef _GNUstep_H_XGOpenGL
#define _GNUstep_H_XGOpenGL

#include <AppKit/NSOpenGL.h>

#define id _gs_avoid_id_collision
#define BOOL XWINDOWSBOOL
#include <GL/glx.h>
#undef id
#undef BOOL

@class NSView;
@class XGXSubWindow;
@class XGGLPixelFormat;

@interface XGGLContext : NSOpenGLContext
{
  GLXContext        glx_context;
  GLXWindow         glx_drawable;
  XGXSubWindow     *xSubWindow;
  XGGLPixelFormat  *pixelFormat;
}

- (GLXContext)glxcontext;

@end

@interface XGGLPixelFormat : NSOpenGLPixelFormat
{
  @public
    union
      {
        GLXFBConfig  *fbconfig;
        XVisualInfo  *visualinfo;
      } configurations;

      int configurationCount;
}
@end

static inline int
GSglxMinorVersion(Display *dpy)
{
  int major, minor;
  Bool result; 
  result = glXQueryVersion (dpy, &major, &minor);

  if (result == False)
  {
    return -1;
  }

  return minor;
}

#endif
/* -*- mode:ObjC -*-
   XGGLContext - backend implementation of NSOpenGLContext

   Copyright (C) 1998,2002 Free Software Foundation, Inc.

   Written by:  Frederic De Jaeger
   Date: Nov 2002
   
   This file is part of the GNU Objective C User Interface Library.

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.
   
   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.
   
   You should have received a copy of the GNU Library General Public
   License along with this library; if not, write to the Free
   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   */


#include "config.h"
#ifdef HAVE_GLX
#include <Foundation/NSDebug.h>
#include <Foundation/NSException.h>
#include <GNUstepGUI/GSDisplayServer.h>
#include <AppKit/NSView.h>
#include <AppKit/NSWindow.h>
#include "x11/XGServerWindow.h"
#include "x11/XGOpenGL.h"

#include <X11/Xlib.h>

//FIXME
//should I store the display ?
#define MAKE_DISPLAY(dpy) Display *dpy;\
  dpy = [(XGServer *)GSCurrentServer() xDisplay];\
  NSAssert(dpy != NULL, NSInternalInconsistencyException)

@interface XGXSubWindow : NSObject
{
  @public
    Window       xwindowid;
    NSView      *attached;
}

+ subwindowOnView:(NSView *)view visualinfo:(XVisualInfo *)xVisualInfo;

- (void) update;

@end

@implementation XGXSubWindow

//We assume that the current context is the same and is an XGServer
- initWithView:(NSView *)view visualinfo:(XVisualInfo *)xVisualInfo
{
  NSRect rect;
  gswindow_device_t *win_info;
  XGServer *server;
  NSWindow *window;
  int x, y, width, height;

  [super init];

  window = [view window];
  NSAssert(window, @"request of an X window attachment on a view that is not on 
a NSWindow");

  if ([view isRotatedOrScaledFromBase])
    {
      [NSException raise: NSInvalidArgumentException
                 format: @"Cannot attach an Xwindow to a view that is rotated 
or scaled"];
    }
  
  server = (XGServer *)GSServerForWindow(window);
  NSAssert(server != nil, NSInternalInconsistencyException);

  NSAssert([server isKindOfClass: [XGServer class]], 
           NSInternalInconsistencyException);

  win_info = [XGServer _windowWithTag: [window windowNumber]];
  NSAssert(win_info, NSInternalInconsistencyException);

  if ([server handlesWindowDecorations] == YES)
    {
      /* The window manager handles window decorations, so the
       * the parent X window is equal to the content view and
       * we must therefore use content view coordinates.
       */
      rect = [view convertRect: [view bounds]
                        toView: [[view window] contentView]];
    }
  else
    {
      /* The GUI library handles window decorations, so the
       * the parent X window is equal to the NSWindow frame
       * and we can use window base coordinates.
       */
      rect = [view convertRect: [view bounds] toView: nil];
    }

  x = NSMinX(rect);
  y = NSHeight(win_info->xframe) - NSMaxY(rect);
  width = NSWidth(rect);
  height = NSHeight(rect);

  XSetWindowAttributes window_attributes;
  window_attributes.border_pixel = 255;
  window_attributes.colormap = XCreateColormap( win_info->display, 
win_info->ident,
                                    xVisualInfo->visual, AllocNone );
  window_attributes.event_mask = StructureNotifyMask;

  int mask = CWBorderPixel | CWColormap | CWEventMask;

//   winid = XCreateWindow(win_info->display, 
DefaultRootWindow(win_info->display),
//                      x, y, width, height, 0, 
//                      CopyFromParent, InputOutput, CopyFromParent, 0, NULL);

  xwindowid = XCreateWindow(win_info->display, win_info->ident,
                        x, y, width, height, 0, 
                        CopyFromParent, InputOutput, xVisualInfo->visual, mask, 
&window_attributes);

  XMapWindow(win_info->display, xwindowid);

  attached = view;

  return self;
}

- (void) map
{
  MAKE_DISPLAY(dpy);
  XMapWindow(dpy, xwindowid);
}

- (void) detach
{
  //FIXME
  //I assume that the current server is correct. 
  MAKE_DISPLAY(dpy);
  attached = nil;
  XDestroyWindow(dpy, xwindowid);
}

- (void) update
{
  NSRect rect;
  gswindow_device_t *win_info;
  GSDisplayServer *server;
  NSWindow *win;
  int x, y, width, height;
  NSAssert(attached, NSInternalInconsistencyException);

  win = [attached window];
  NSAssert1(win, @"%@'s window is nil now!", attached);

  NSAssert1(![attached isRotatedOrScaledFromBase],
            @"%@ is rotated or scaled, now!", attached);
  
  server = GSServerForWindow(win);
  NSAssert(server != nil, NSInternalInconsistencyException);

  NSAssert([server isKindOfClass: [XGServer class]], 
           NSInternalInconsistencyException);

  //FIXME
  //we should check that the window hasn't changed, maybe.

  win_info = [XGServer _windowWithTag: [win windowNumber]];
  NSAssert(win_info, NSInternalInconsistencyException);

  if ([server handlesWindowDecorations] == YES)
    {
      /* The window manager handles window decorations, so the
       * the parent X window is equal to the content view and
       * we must therefore use content view coordinates.
       */
      rect = [attached convertRect: [attached bounds]
                            toView: [[attached window] contentView]];
    }
  else
    {
      /* The GUI library handles window decorations, so the
       * the parent X window is equal to the NSWindow frame
       * and we can use window base coordinates.
       */
      rect = [attached convertRect: [attached bounds] toView: nil];
    }

  x = NSMinX(rect);
  y = NSHeight(win_info->xframe) - NSMaxY(rect);
  width = NSWidth(rect);
  height = NSHeight(rect);

  
  XMoveResizeWindow(win_info->display, xwindowid,x, y, width, height);
}

- (void) dealloc
{
  NSDebugMLLog(@"GLX", @"deallocating");
  [self detach];
  [super dealloc];
}

+ subwindowOnView:(NSView *)view visualinfo:(XVisualInfo *)xVisualInfo
{
  XGXSubWindow *win = [[self alloc] initWithView:view visualinfo:xVisualInfo ];

  return AUTORELEASE(win);
}
@end

//FIXME:
//should be on per thread basis.
static XGGLContext *currentGLContext;


@implementation XGGLContext

+ (void)clearCurrentContext
{
  MAKE_DISPLAY(dpy);

  if (GSglxMinorVersion (dpy) >= 3)
    {
      glXMakeContextCurrent(dpy, None, None, NULL);
    }
  else
    {
      glXMakeCurrent(dpy, None, NULL);
    }

  currentGLContext = nil;
}

+ (NSOpenGLContext *)currentContext
{
  return currentGLContext;
}

- (void) _detach
{
  if (xSubWindow)
    {
      MAKE_DISPLAY(dpy);

      if (currentGLContext == self)
            {
              [XGGLContext clearCurrentContext];
            }
      //      glXDestroyWindow(dpy, glx_drawable);
      glx_drawable = None;
      DESTROY(xSubWindow);
    }
}

- (GLXContext)glxcontext
{
    return glx_context;
}

- (void)clearDrawable
{
  [self _detach];
}

- (void)copyAttributesFromContext:(NSOpenGLContext *)context 
                         withMask:(unsigned long)mask
{
  GLXContext other;
  MAKE_DISPLAY(dpy);

  if (context == nil ||  ![context isKindOfClass: [XGGLContext class]])
    [NSException raise: NSInvalidArgumentException
                 format: @"%@ is an invalid context", context];

  other = ((XGGLContext *)context)->glx_context;

  glXCopyContext(dpy, other, glx_context, mask);
}

- (void)createTexture:(unsigned long)target 
             fromView:(NSView*)view 
       internalFormat:(unsigned long)format
{
  [self notImplemented: _cmd];
}


- (int)currentVirtualScreen
{
  [self notImplemented: _cmd];

  return 0;
}

- (void)flushBuffer
{
  MAKE_DISPLAY(dpy);

  glXSwapBuffers(dpy, glx_drawable);
}


- (void)getValues:(long *)vals 
     forParameter:(NSOpenGLContextParameter)param
{
  //  TODO
  [self notImplemented: _cmd];
}


- (id)initWithFormat: (NSOpenGLPixelFormat *)_format 
            shareContext: (NSOpenGLContext *)share
{
  [super init];

  glx_context = None;
  
  if (_format && [_format isKindOfClass: [XGGLPixelFormat class]])
    {
      MAKE_DISPLAY(dpy);
      ASSIGN(pixelFormat, (XGGLPixelFormat *)_format);
      //FIXME: allow index mode and sharing

      if (GSglxMinorVersion (dpy) >= 3)
        {
              glx_context = glXCreateNewContext(dpy, 
pixelFormat->configurations.fbconfig[0], 
                                                                GLX_RGBA_TYPE, 
[ (XGGLContext *)share glxcontext ], YES);
        }
      else
        {
              glx_context = glXCreateContext(dpy, 
pixelFormat->configurations.visualinfo, [ (XGGLContext *)share glxcontext ], 
GL_TRUE);
        }

      return self;
    }
  else
    {
      NSDebugMLLog(@"GLX", @"invalid format %@", _format);
      RELEASE(self);

      return nil;
    }
}


- (void) dealloc
{
  NSDebugMLLog(@"GLX", @"deallocating");
  [self _detach];
  RELEASE(pixelFormat);

  if (glx_context != None)
    {
      MAKE_DISPLAY(dpy);
      glXDestroyContext(dpy, glx_context);
    }

  [super dealloc];
}

- (void) makeCurrentContext
{
  MAKE_DISPLAY(dpy);

  if (xSubWindow == nil)
    [NSException raise: NSGenericException
                 format: @"GL Context is not bind, cannot be made current"];
  
  NSAssert(glx_context != None && glx_drawable != None,
           NSInternalInconsistencyException);

  if (GSglxMinorVersion (dpy) >= 3)
    {
      NSDebugMLLog(@"GLX", @"before glXMakeContextCurrent");
      glXMakeContextCurrent(dpy, glx_drawable, glx_drawable, glx_context);
      NSDebugMLLog(@"GLX", @"after glXMakeContextCurrent");
    }
  else
    {
      NSDebugMLLog(@"GLX", @"before glXMakeCurrent");
      glXMakeCurrent(dpy, glx_drawable, glx_context);
      NSDebugMLLog(@"GLX", @"after glXMakeCurrent");
    }

//   NSAssert(glx_context != None,   NSInternalInconsistencyException);

//   glXMakeCurrent(dpy, xsubwin->winid, glx_context);

  currentGLContext = self;
}


- (void)setCurrentVirtualScreen:(int)screen
{
  [self notImplemented: _cmd];
}


- (void)setFullScreen
{
  [self notImplemented: _cmd];
}


- (void)setOffScreen:(void *)baseaddr 
               width:(long)width 
              height:(long)height 
            rowbytes:(long)rowbytes
{
  [self notImplemented: _cmd];
}


- (void)setValues:(const long *)vals 
     forParameter:(NSOpenGLContextParameter)param
{
  [self notImplemented: _cmd];
}


- (void)setView:(NSView *)view
{
  XGXSubWindow *win;
  MAKE_DISPLAY(dpy);

  if (!view)
    [NSException raise: NSInvalidArgumentException
                 format: @"setView called with a nil value"];

  NSAssert(pixelFormat, NSInternalInconsistencyException);

  XVisualInfo * xvinfo;

  if (GSglxMinorVersion (dpy) >= 3)
    {
      xvinfo = 
glXGetVisualFromFBConfig(dpy,pixelFormat->configurations.fbconfig[0]);
    }
  else
    {
      xvinfo = pixelFormat->configurations.visualinfo;
    }


  win = [XGXSubWindow subwindowOnView:view visualinfo:xvinfo ];
  ASSIGN(xSubWindow, win);

  glx_drawable = glXCreateWindow( dpy, pixelFormat->configurations.fbconfig[0], 
win->xwindowid, NULL );

  //glx_drawable = xSubWindow->xwindowid;

//FIXME
//The following line should be the good one.  But it crashes my X server...

//   glx_drawable = glXCreateWindow(dpy, *format->conf_tab, xsubwin->winid,
//                               NULL);
  NSDebugMLLog(@"GLX", @"glx_window : %u", glx_drawable);
}


- (void)update
{
  [xSubWindow update];
}


- (NSView *)view
{
  if (xSubWindow)
    {
      return xSubWindow->attached;
    }
  else
    {
      return nil;
    }
}

@end
#endif
/* -*- mode:ObjC -*-
   XGGLContext - backend implementation of NSOpenGLContext

   Copyright (C) 1998,2002 Free Software Foundation, Inc.

   Written by:  Frederic De Jaeger
   Date: Nov 2002
   
   This file is part of the GNU Objective C User Interface Library.

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.
   
   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.
   
   You should have received a copy of the GNU Library General Public
   License along with this library; if not, write to the Free
   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   */

#include "config.h"
#ifdef HAVE_GLX
#include <Foundation/NSDebug.h>
#include <Foundation/NSException.h>
#include <Foundation/NSData.h>
#include <GNUstepGUI/GSDisplayServer.h>
#include "x11/XGServer.h"
#include "x11/XGOpenGL.h"

#include <X11/Xlib.h>

#define MAKE_DISPLAY(dpy) Display *dpy;\
  dpy = [(XGServer *)GSCurrentServer() xDisplay];\
  NSAssert(dpy != NULL, NSInternalInconsistencyException)


@implementation XGGLPixelFormat

/* FIXME:
     we assume that the ABI of NSOpenGLPixelFormatAttribute matches the ABI 
     of glX. Apparently, this is true for the most useful attributes.
*/

- (void) getValues: (GLint *)vals 
      forAttribute: (NSOpenGLPixelFormatAttribute)attrib 
  forVirtualScreen: (GLint)screen
{
  MAKE_DISPLAY(dpy);

  NSAssert(((GSglxMinorVersion (dpy) >= 3) ? (void *)configurations.fbconfig : 
(void *)configurations.visualinfo) != NULL
                && configurationCount > 0,
            NSInternalInconsistencyException);

  if (GSglxMinorVersion (dpy) >= 3)
    {
      glXGetFBConfigAttrib(dpy, configurations.fbconfig[0], attrib, vals);
    }
  else
    {
      glXGetConfig(dpy, configurations.visualinfo, attrib, vals);
    }
}

- (id)initWithAttributes:(NSOpenGLPixelFormatAttribute *)attribs
{
  int v1, v2;
  int AccumSize;
  NSOpenGLPixelFormatAttribute *ptr = attribs;
  NSMutableData *data = [NSMutableData data];
  MAKE_DISPLAY(dpy);

#define append(a, b) do {v1 = a;v2 = b;[data appendBytes: &v1 length: 
sizeof(v1)];\
  [data appendBytes: &v2 length: sizeof(v2)];} while (0)

#define append1(a) do {v1 = a;[data appendBytes: &v1 length: sizeof(v1)];} 
while (0)

  if (GSglxMinorVersion (dpy) < 3)
    {
        append1 (GLX_RGBA);
    }
  else
    {
        append(GLX_RENDER_TYPE, GLX_RGBA_BIT);
        append(GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT|GLX_PIXMAP_BIT);
      //  append(GLX_X_RENDERABLE,YES);
      //append(GLX_X_VISUAL_TYPE,GLX_TRUE_COLOR);
    }

  while (*ptr)
    {
      switch(*ptr)
        {
        // it means all the same on GLX - there is no diffrent here
        case NSOpenGLPFASingleRenderer:
        case NSOpenGLPFAAllRenderers:
        case NSOpenGLPFAAccelerated:
      if ( GSglxMinorVersion (dpy) < 3 )
          append(GLX_USE_GL,YES);
          break;
        case  NSOpenGLPFADoubleBuffer:
          append(GLX_DOUBLEBUFFER, YES);
          break;
        case NSOpenGLPFAStereo:
          append(GLX_STEREO, YES);
          break;
        case NSOpenGLPFAAuxBuffers:
          ptr++;
          append(GLX_AUX_BUFFERS, *ptr);
          break;
        case NSOpenGLPFAColorSize:
          ptr++;
          append(GLX_RED_SIZE, *ptr);
          append(GLX_GREEN_SIZE, *ptr);
          append(GLX_BLUE_SIZE, *ptr);
          break;
        case NSOpenGLPFAAlphaSize:
          ptr++;
          append(GLX_ALPHA_SIZE, *ptr);
          break;
        case NSOpenGLPFADepthSize:
          ptr++;
          append(GLX_DEPTH_SIZE, *ptr);
          break;
        case NSOpenGLPFAStencilSize:
          ptr++;
          append(GLX_STENCIL_SIZE, *ptr);
          break;
        case NSOpenGLPFAAccumSize:
          ptr++;
          //has to been tested - I did it in that way....
          //FIXME?  I don't understand...
          //append(GLX_ACCUM_RED_SIZE, *ptr/3);
          //append(GLX_ACCUM_GREEN_SIZE, *ptr/3);
          //append(GLX_ACCUM_BLUE_SIZE, *ptr/3);
        AccumSize=*ptr;  
        switch (AccumSize)
                {
                case 8:
                        append(GLX_ACCUM_RED_SIZE, 3);
                        append(GLX_ACCUM_GREEN_SIZE, 3);
                        append(GLX_ACCUM_BLUE_SIZE, 2);
                        append(GLX_ACCUM_ALPHA_SIZE, 0);
                        break;
                case 15:
                case 16:
                        append(GLX_ACCUM_RED_SIZE, 5);
                        append(GLX_ACCUM_GREEN_SIZE, 5);
                        append(GLX_ACCUM_BLUE_SIZE, 5);
                        append(GLX_ACCUM_ALPHA_SIZE, 0);
                        break;
                case 24:
                        append(GLX_ACCUM_RED_SIZE, 8);
                        append(GLX_ACCUM_GREEN_SIZE, 8);
                        append(GLX_ACCUM_BLUE_SIZE, 8);
                        append(GLX_ACCUM_ALPHA_SIZE, 0);
                        break;
                case 32:
                        append(GLX_ACCUM_RED_SIZE, 8);
                        append(GLX_ACCUM_GREEN_SIZE, 8);
                        append(GLX_ACCUM_BLUE_SIZE, 8);
                        append(GLX_ACCUM_ALPHA_SIZE, 8);
                        break;
                }
                break;
        //can not be handle by X11
        case NSOpenGLPFAMinimumPolicy:
          break;
        // can not be handle by X11
        case NSOpenGLPFAMaximumPolicy:
          break;

          //FIXME all of this stuff...
        case NSOpenGLPFAOffScreen:
        case NSOpenGLPFAFullScreen:
        case NSOpenGLPFASampleBuffers:
        case NSOpenGLPFASamples:
        case NSOpenGLPFAAuxDepthStencil:
        case NSOpenGLPFARendererID:
        case NSOpenGLPFANoRecovery:
        case NSOpenGLPFAClosestPolicy:
        case NSOpenGLPFARobust:
        case NSOpenGLPFABackingStore:
        case NSOpenGLPFAMPSafe:
        case NSOpenGLPFAWindow:
        case NSOpenGLPFAMultiScreen:
        case NSOpenGLPFACompliant:
        case NSOpenGLPFAScreenMask:
        case NSOpenGLPFAVirtualScreenCount:
          break;
        }
      ptr ++;
    }

  append1(None);

  //FIXME, what screen number ?
  if (GSglxMinorVersion (dpy) >= 3)
    {
      configurations.fbconfig = glXChooseFBConfig(dpy, DefaultScreen(dpy), 
[data mutableBytes], &configurationCount);
    }
  else
    {
      configurations.visualinfo = glXChooseVisual(dpy, DefaultScreen(dpy), 
[data mutableBytes]);
    }
  
  if (((GSglxMinorVersion (dpy) >= 3) ? (void *)configurations.fbconfig : (void 
*)configurations.visualinfo) == NULL)
    {
      NSDebugMLLog(@"GLX", @"no pixel format found matching what is required");
      RELEASE(self);

      return nil;
    }
  else
    {
      NSDebugMLLog(@"GLX", @"We found %d pixel formats", configurationCount);
      
      return self;
    }
}

- (void) dealloc
{
  //FIXME       
  //are we sure that X Connection is still up here ?
  MAKE_DISPLAY(dpy);

  if (GSglxMinorVersion (dpy) >= 3)
    {
      XFree (configurations.fbconfig);
    }
  else
    {
      XFree (configurations.visualinfo);
    }

  NSDebugMLLog(@"GLX", @"deallocation");
  [super dealloc];
}

- (int)numberOfVirtualScreens
{
  //  [self notImplemented: _cmd];
  //FIXME
  //This looks like a reasonable value to return...
  return 1;
}

@end
#endif

reply via email to

[Prev in Thread] Current Thread [Next in Thread]