OpenGL sub-windows: prevent back-store flush, handle expose events, and small fix/improvements

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/back/trunk@28036 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
xgl 2009-03-04 09:58:41 +00:00
parent fd95b99bca
commit 6acde03c4d
12 changed files with 282 additions and 57 deletions

View file

@ -1,3 +1,24 @@
2009-03-04 Xavier Glattard <xavier.glattard@online.fr>
* Source/x11/XGGLContext.m,
* Source/x11/XGServerWindow.m,
* Source/x11/XGServerEvent.m,
* Source/win32/w32_GLcontext.m,
* Source/win32/w32_windowdisplay.m,
* Source/win32/WIN32Server.m:
Two improvements related to OpenGL.
1) prevent the backing store to be flushed after a call to [-drawRect:]
(and fix a small bug is win32 window style)
2) handle expose/paint events with retained/buffered backing store.
* Source/x11/XGGLFormat.m,
* Source/win32/w32_GLformat.m:
Declare some new pixel format attributes.
* Source/x11/XGGLContext.m,
* Source/win32/w32_GLcontext.m:
Undo Rev27944 related to NSRECT conversion.
2009-02-21 Fred Kiefer <FredKiefer@gmx.de>
* Source/x11/XGGLContext.m (XGXSubWindow -initWithView:visualInfo:):

View file

@ -46,6 +46,7 @@
HGLRC wgl_context;
Win32Subwindow *wsubwin;
Win32GLPixelFormat *format;
BOOL saved_ignores_backing;
}
@end

View file

@ -46,6 +46,7 @@
GLXWindow glx_drawable;
XGXSubWindow *xSubWindow;
XGGLPixelFormat *pixelFormat;
BOOL saved_ignores_backing;
}
- (GLXContext)glxcontext;

View file

@ -122,7 +122,7 @@ typedef struct _gswindow_device_t {
+ (gswindow_device_t *) _windowForXWindow: (Window)xWindow;
+ (gswindow_device_t *) _windowForXParent: (Window)xWindow;
+ (gswindow_device_t *) _windowWithTag: (int)windowNumber;
- (void) _addExposedRectangle: (XRectangle)rectangle : (int)win;
- (void) _addExposedRectangle: (XRectangle)rectangle : (int)win : (BOOL) ignoreBacking;
- (void) _processExposedRectangles: (int)win;
- (void) _initializeCursorForXWindow: (Window) win;
- (void) _destroyServerWindows;

View file

@ -434,7 +434,7 @@ NSLog(@"Callback");
DWORD wstyle = 0;
if ([self handlesWindowDecorations] == NO)
return WS_POPUP;
return WS_POPUP | WS_CLIPCHILDREN;
if (style == 0)
wstyle = WS_POPUP;

View file

@ -130,8 +130,22 @@ LRESULT CALLBACK win32SubwindowProc(
NSAssert(atom, @"MS window class not found !");
GetClientRect((HWND)[win windowNumber], &parent_rect);
rect = [view convertRect: [view bounds] toView: nil];
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: [[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 = [view convertRect: [view bounds] toView: nil];
}
x = NSMinX(rect);
y = (parent_rect.bottom - parent_rect.top) - NSMaxY(rect);
width = NSWidth(rect);
@ -392,6 +406,7 @@ static Win32GLContext *currentGLContext;
- (void)setView:(NSView *)view
{
Win32Subwindow *win;
NSView *current_view;
if (!view)
[NSException raise: NSInvalidArgumentException
@ -399,7 +414,14 @@ static Win32GLContext *currentGLContext;
NSAssert(format, NSInternalInconsistencyException);
win = [Win32Subwindow subwindowOnView: (NSOpenGLView*) view];
current_view = [self view];
if ( current_view != nil )
{
[current_view _setIgnoresBacking: saved_ignores_backing];
}
ASSIGN(wsubwin, win);
saved_ignores_backing = [view _ignoresBacking];
[view _setIgnoresBacking: YES];
// {
// GLXFBConfig *conf_tab;
@ -525,17 +547,20 @@ LRESULT CALLBACK win32SubwindowProc(
return TRUE;
}
break;*/
/* case WM_PAINT:
case WM_PAINT:
{
PAINTSTRUCT ps;
BeginPaint(hWnd, &ps);
if ((wsubwin->context->wgl_context) {
redraw();
}
EndPaint(hWnd, &ps);
return 0;
RECT wr;
RECT ir;
if ( GetWindowRect(hWnd,&wr) && GetUpdateRect(hWnd, &ir, FALSE) )
{
ir.top += wr.top;
ir.left += wr.left;
InvalidateRect( GetParent(hWnd), &ir,FALSE );
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;*/
break;
/* case WM_CHAR:
// handle keyboard input
switch ((int)wParam) {

View file

@ -36,6 +36,7 @@
static void attributesNS2WGL( NSOpenGLPixelFormatAttribute *attribs, LPPIXELFORMATDESCRIPTOR ppfd )
{
// TODO : switch to wglChoosePixelFormatEXT
NSOpenGLPixelFormatAttribute *ptr = attribs;
ppfd->nSize = sizeof(PIXELFORMATDESCRIPTOR);
@ -56,6 +57,9 @@ static void attributesNS2WGL( NSOpenGLPixelFormatAttribute *attribs, LPPIXELFORM
case NSOpenGLPFAOffScreen:
ppfd->dwFlags |= PFD_DRAW_TO_BITMAP;
break;
case NSOpenGLPFAPixelBuffer: // TODO
//ppfd->dwFlags |= PFD_DRAW_TO_WINDOW;
break;
case NSOpenGLPFASingleRenderer:
case NSOpenGLPFAAllRenderers:
case NSOpenGLPFAAccelerated:
@ -67,6 +71,9 @@ static void attributesNS2WGL( NSOpenGLPixelFormatAttribute *attribs, LPPIXELFORM
case NSOpenGLPFAStereo:
ppfd->dwFlags |= PFD_STEREO;
break;
case NSOpenGLPFABackingStore:
ppfd->dwFlags |= PFD_SWAP_COPY;
break;
case NSOpenGLPFAAuxBuffers:
ptr++;
ppfd->cAuxBuffers = *ptr;
@ -136,12 +143,17 @@ static void attributesNS2WGL( NSOpenGLPixelFormatAttribute *attribs, LPPIXELFORM
case NSOpenGLPFANoRecovery:
case NSOpenGLPFAClosestPolicy:
case NSOpenGLPFARobust:
case NSOpenGLPFABackingStore:
case NSOpenGLPFAMPSafe:
case NSOpenGLPFAMultiScreen:
case NSOpenGLPFACompliant:
case NSOpenGLPFAScreenMask:
case NSOpenGLPFAVirtualScreenCount:
case NSOpenGLPFAAllowOfflineRenderers:
case NSOpenGLPFAColorFloat:
case NSOpenGLPFAMultisample:
case NSOpenGLPFASupersample:
case NSOpenGLPFASampleAlpha:
break;
}
ptr ++;
@ -239,6 +251,8 @@ static void attributesWGL2NS( LPPIXELFORMATDESCRIPTOR ppfd, NSOpenGLPixelFormatA
- (void) _setDrawable: (HDC) aDrawable
{
// TODO : switch to wglChoosePixelFormatEXT
NSCAssert(
wgl_pixelformat = ChoosePixelFormat(aDrawable, &pfd),
@"ChoosePixelFormat failed.");

View file

@ -131,27 +131,14 @@ invalidateWindow(WIN32Server *svr, HWND hwnd, RECT rect)
- (void) decodeWM_PAINTParams: (WPARAM)wParam : (LPARAM)lParam : (HWND)hwnd
{
RECT rect;
PAINTSTRUCT pPaint;
/* FK:
I am not sure if calling BeginPaint/EndPaint here is the best
way to handle updates. These functions correspond more closely
to the lockFocus/unlockFocus methods and should rather be used there.
//InvalidateRect(hwnd, rect, YES);
// validate the whole window, for in some cases an infinite series
// of WM_PAINT is triggered
//ValidateRect(hwnd, NULL);
*/
if (GetUpdateRect(hwnd, &rect, TRUE))
{
BeginPaint(hwnd, &pPaint);
// Perform drawing (or blitting into buffer if needed)
invalidateWindow(self, hwnd, rect);
EndPaint(hwnd, &pPaint);
NSRect r = MSWindowRectToGS(self, hwnd, rect);
NSWindow *window = GSWindowWithNumber((int)hwnd);
[[[window contentView] superview] setNeedsDisplayInRect: r];
}
flags._eventHandled = YES;
//flags._eventHandled = YES; -->DefWindowProc validates the event
}
- (void) decodeWM_SYNCPAINTParams: (WPARAM)wParam : (LPARAM)lParam : (HWND)hwnd

View file

@ -101,7 +101,9 @@
window_attributes.colormap = XCreateColormap(win_info->display,
win_info->ident,
xVisualInfo->visual, AllocNone);
window_attributes.event_mask = StructureNotifyMask;
window_attributes.event_mask = StructureNotifyMask
| VisibilityChangeMask
| ExposureMask;
mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
@ -215,11 +217,15 @@ static XGGLContext *currentGLContext;
if (GSglxMinorVersion(dpy) >= 3)
{
glXMakeContextCurrent(dpy, None, None, NULL);
if ( !glXMakeContextCurrent(dpy, None, None, NULL) )
NSDebugMLLog( @"GLX", @"Can not clear current GL context - Errror %u",
glGetError() );
}
else
{
glXMakeCurrent(dpy, None, NULL);
if ( !glXMakeCurrent(dpy, None, NULL) )
NSDebugMLLog( @"GLX", @"Can not clear current GL context - Errror %u",
glGetError() );
}
currentGLContext = nil;
@ -268,6 +274,12 @@ static XGGLContext *currentGLContext;
glXCopyContext(dpy, ((XGGLContext *)context)->glx_context,
glx_context, mask);
GLint error = glGetError();
if ( error != GL_NO_ERROR )
NSDebugMLLog( @"GLX", @"Can not copy GL context %@ from context %@ - Errror %u",
self, context, error );
}
- (void)createTexture:(unsigned long)target
@ -290,6 +302,63 @@ static XGGLContext *currentGLContext;
MAKE_DISPLAY(dpy);
glXSwapBuffers(dpy, glx_drawable);
#if 0
// FIXME Not with Mesa Xlib sofware driver !
// TODO Use EXT_framebuffer_blit if available
if ( _doubleBuffer )
{
if ( _backingStore )
{
GLint rBuf,dBuf;
GLint viewport[4];
GLfloat raster_pos[4];
/* save viewport */
glGetIntegerv(GL_VIEWPORT, viewport);
/* save old raster position */
glGetFloatv(GL_CURRENT_RASTER_POSITION, raster_pos);
/* set raster position */
glRasterPos4f(0.0, 0.0, 0.0, 1.0);
/* save target/source buffers */
glGetIntegerv( GL_READ_BUFFER, &rBuf );
glGetIntegerv( GL_DRAW_BUFFER, &wBuf );
/* set projection matrix */
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity() ;
gluOrtho2D(0, viewport[2], 0, viewport[3]);
/* set modelview matrix */
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
//FIXME copy depth, stencil?
glReadBuffer (GL_FRONT_LEFT);
glDrawBuffer (GL_BACK_LEFT);
glCopyPixels(0, 0, viewport[2], viewport[3], GL_COLOR);
if ( _stereo )
{
glReadBuffer (GL_FRONT_RIGHT);
glDrawBuffer (GL_BACK_RIGHT);
glCopyPixels(0, 0, viewport[2], viewport[3], GL_COLOR);
}
/* restore target/source buffers */
glReadBuffer (rBuf);
glDrawBuffer (dBuf);
/* restore old raster position */
glRasterPos4fv(raster_pos);
/* restore old matrices */
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
/* restore viewport */
glViewport(viewport[0],viewport[1],viewport[2],viewport[3]);
}
}
#endif
}
@ -355,15 +424,19 @@ static XGGLContext *currentGLContext;
if (GSglxMinorVersion(dpy) >= 3)
{
NSDebugMLLog(@"GLX", @"before glXMakeContextCurrent");
glXMakeContextCurrent(dpy, glx_drawable, glx_drawable, glx_context);
NSDebugMLLog(@"GLX", @"after glXMakeContextCurrent");
//NSDebugMLLog(@"GLX", @"before glXMakeContextCurrent");
if ( !glXMakeContextCurrent(dpy, glx_drawable, glx_drawable, glx_context) )
NSDebugMLLog( @"GLX", @"Can not make GL context %@ current - Errror %u",
self, glGetError() );
//NSDebugMLLog(@"GLX", @"after glXMakeContextCurrent");
}
else
{
NSDebugMLLog(@"GLX", @"before glXMakeCurrent");
glXMakeCurrent(dpy, glx_drawable, glx_context);
NSDebugMLLog(@"GLX", @"after glXMakeCurrent");
//NSDebugMLLog(@"GLX", @"before glXMakeCurrent");
if ( !glXMakeCurrent(dpy, glx_drawable, glx_context) )
NSDebugMLLog( @"GLX", @"Can not make GL context %@ current - Errror %u",
self, glGetError() );
//NSDebugMLLog(@"GLX", @"after glXMakeCurrent");
}
currentGLContext = self;
@ -395,15 +468,22 @@ static XGGLContext *currentGLContext;
- (void)setView:(NSView *)view
{
NSView *current_view;
if (!view)
[NSException raise: NSInvalidArgumentException
format: @"setView called with a nil value"];
NSAssert(pixelFormat, NSInternalInconsistencyException);
current_view = [self view];
if ( current_view != nil )
{
[current_view _setIgnoresBacking: saved_ignores_backing];
}
ASSIGN(xSubWindow, [XGXSubWindow subwindowOnView: view
visualinfo: [pixelFormat xvinfo]]);
glx_drawable = [pixelFormat drawableForWindow: xSubWindow->xwindowid];
saved_ignores_backing = [view _ignoresBacking];
[view _setIgnoresBacking: YES];
NSDebugMLLog(@"GLX", @"glx_window : %u", glx_drawable);
}

View file

@ -52,6 +52,7 @@
forVirtualScreen: (GLint)screen
{
MAKE_DISPLAY(dpy);
GLint error;
NSAssert(((GSglxMinorVersion (dpy) >= 3) ? (void *)configurations.fbconfig : (void *)configurations.visualinfo) != NULL
&& configurationCount > 0,
@ -59,11 +60,17 @@
if (GSglxMinorVersion(dpy) >= 3)
{
glXGetFBConfigAttrib(dpy, configurations.fbconfig[0], attrib, vals);
error = glXGetFBConfigAttrib(dpy, configurations.fbconfig[0], attrib, vals);
if ( error != 0 )
NSDebugMLLog( @"GLX", @"Can not get FB attribute for pixel format %@ - Errror %u",
self, error );
}
else
{
glXGetConfig(dpy, configurations.visualinfo, attrib, vals);
if ( error != 0 )
NSDebugMLLog( @"GLX", @"Can not get FB attribute for pixel format %@ - Errror %u",
self, error );
}
}
@ -73,6 +80,7 @@
NSOpenGLPixelFormatAttribute *ptr = attribs;
NSMutableData *data = [NSMutableData data];
MAKE_DISPLAY(dpy);
int drawable_type;
#define append(a, b) do {int v1 = a; int v2 = b; [data appendBytes: &v1 length: sizeof(v1)];\
[data appendBytes: &v2 length: sizeof(v2)];} while (0)
@ -86,8 +94,8 @@
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_DRAWABLE_TYPE, GLX_WINDOW_BIT|GLX_PIXMAP_BIT);
//append(GLX_X_RENDERABLE,YES);
//append(GLX_X_VISUAL_TYPE,GLX_TRUE_COLOR);
}
@ -167,6 +175,15 @@
break;
}
break;
case NSOpenGLPFAPixelBuffer:
ptr++;
drawable_type |= GLX_PBUFFER_BIT;
break;
case NSOpenGLPFAOffScreen:
ptr++;
drawable_type |= GLX_PIXMAP_BIT;
break;
//can not be handle by X11
case NSOpenGLPFAMinimumPolicy:
break;
@ -175,7 +192,6 @@
break;
//FIXME all of this stuff...
case NSOpenGLPFAOffScreen:
case NSOpenGLPFAFullScreen:
case NSOpenGLPFASampleBuffers:
case NSOpenGLPFASamples:
@ -191,11 +207,21 @@
case NSOpenGLPFACompliant:
case NSOpenGLPFAScreenMask:
case NSOpenGLPFAVirtualScreenCount:
case NSOpenGLPFAAllowOfflineRenderers:
case NSOpenGLPFAColorFloat:
case NSOpenGLPFAMultisample:
case NSOpenGLPFASupersample:
case NSOpenGLPFASampleAlpha:
break;
}
ptr ++;
}
if ( drawable_type )
{
//append(GLX_DRAWABLE_TYPE,drawable_type);
}
append1(None);
//FIXME, what screen number ?
@ -204,11 +230,19 @@
configurations.fbconfig = glXChooseFBConfig(dpy, DefaultScreen(dpy),
[data mutableBytes],
&configurationCount);
if ( configurations.fbconfig == NULL )
NSDebugMLLog( @"GLX", @"Can not choose FB config for pixel format %@",
self );
}
else
{
configurations.visualinfo = glXChooseVisual(dpy, DefaultScreen(dpy),
[data mutableBytes]);
if((void *)configurations.visualinfo != NULL)
configurationCount = 1;
else
NSDebugMLLog( @"GLX", @"Can not choose FB config for pixel format %@",
self );
}
if (((GSglxMinorVersion (dpy) >= 3) ? (void *)configurations.fbconfig :
@ -243,33 +277,46 @@
- (GLXContext)createGLXContext: (XGGLContext *)share
{
GLXContext context;
MAKE_DISPLAY(dpy);
if (GSglxMinorVersion(dpy) >= 3)
{
return glXCreateNewContext(dpy, configurations.fbconfig[0],
context = glXCreateNewContext(dpy, configurations.fbconfig[0],
GLX_RGBA_TYPE, [share glxcontext], YES);
}
else
{
return glXCreateContext(dpy, configurations.visualinfo,
context = glXCreateContext(dpy, configurations.visualinfo,
[share glxcontext], GL_TRUE);
}
if ( context == NULL )
NSDebugMLLog( @"GLX", @"Can not create GL context for pixel format %@ - Errror %u",
self, glGetError() );
return context;
}
- (GLXWindow) drawableForWindow: (Window)xwindowid
{
GLXWindow win;
MAKE_DISPLAY(dpy);
if (GSglxMinorVersion(dpy) >= 3)
{
return glXCreateWindow(dpy, configurations.fbconfig[0],
win = glXCreateWindow(dpy, configurations.fbconfig[0],
xwindowid, NULL);
}
else
{
return xwindowid;
win = xwindowid;
}
GLint error = glGetError();
if ( error != GL_NO_ERROR )
NSDebugMLLog( @"GLX", @"Can not create GL window for pixel format %@ - Errror %u",
self, error );
return win;
}
- (void) dealloc

View file

@ -932,6 +932,22 @@ static int check_modifier (XEvent *xEvent, KeySym key_sym)
generic.cachedWindow
= [XGServer _windowForXWindow:xEvent.xvisibility.window];
}
// sub-window ?
{
Window xw;
xw = xEvent.xvisibility.window;
while (cWin == 0)
{
Window rw, *cw; unsigned int nc;
if ( !XQueryTree(dpy, xw, &rw, &xw, &cw, &nc) )
continue;
if ( cw != NULL )
XFree(cw);
generic.cachedWindow
= [XGServer _windowForXWindow:xw];
}
}
if (cWin != 0)
cWin->visibility = xEvent.xvisibility.state;
break;
@ -942,24 +958,60 @@ static int check_modifier (XEvent *xEvent, KeySym key_sym)
NSDebugLLog(@"NSEvent", @"%d Expose\n",
xEvent.xexpose.window);
{
BOOL isSubWindow;
if (cWin == 0 || xEvent.xexpose.window != cWin->ident)
{
generic.cachedWindow
= [XGServer _windowForXWindow:xEvent.xexpose.window];
}
// sub-window ?
{
Window xw;
xw = xEvent.xexpose.window;
while (cWin == 0)
{
Window rw, *cw; unsigned int nc;
if ( !XQueryTree(dpy, xw, &rw, &xw, &cw, &nc) )
continue;
if ( cw != NULL )
XFree(cw);
generic.cachedWindow
= [XGServer _windowForXWindow:xw];
}
if ( xw == xEvent.xexpose.window )
{
isSubWindow = YES;
}
}
if (cWin != 0)
{
XRectangle rectangle;
rectangle.x = xEvent.xexpose.x;
rectangle.y = xEvent.xexpose.y;
if ( isSubWindow )
{
rectangle.x = xEvent.xexpose.x;
rectangle.y = xEvent.xexpose.y;
}
else
{
// assume no border
XWindowAttributes wa;
XGetWindowAttributes(dpy,xEvent.xexpose.window,&wa);
rectangle.x = xEvent.xexpose.x+wa.x;
rectangle.y = xEvent.xexpose.y+wa.y;
}
rectangle.width = xEvent.xexpose.width;
rectangle.height = xEvent.xexpose.height;
NSDebugLLog(@"NSEvent", @"Expose frame %d %d %d %d\n",
rectangle.x, rectangle.y,
rectangle.width, rectangle.height);
#if 1
[self _addExposedRectangle: rectangle : cWin->number];
// ignore backing if sub-window
[self _addExposedRectangle: rectangle : cWin->number : isSubWindow];
if (xEvent.xexpose.count == 0)
[self _processExposedRectangles: cWin->number];

View file

@ -3426,7 +3426,7 @@ static BOOL didCreatePixmaps;
}
// process expose event
- (void) _addExposedRectangle: (XRectangle)rectangle : (int)win
- (void) _addExposedRectangle: (XRectangle)rectangle : (int)win : (BOOL) ignoreBacking
{
gswindow_device_t *window;
@ -3434,7 +3434,7 @@ static BOOL didCreatePixmaps;
if (!window)
return;
if (window->type != NSBackingStoreNonretained)
if (!ignoreBacking && window->type != NSBackingStoreNonretained)
{
XGCValues values;
unsigned long valuemask;
@ -3559,9 +3559,6 @@ static BOOL didCreatePixmaps;
if (!window)
return;
if (window->type != NSBackingStoreNonretained)
return;
// Set the clipping path to the exposed rectangles
// so that further drawing will not affect the non-exposed region
XSetRegion (dpy, window->gc, window->region);