Use a buffered window. This fixes the last of the GUI issues. Allows resizing and is very careful to update the graphics context only in the main thread (in this case, SM's main thread, not the GUI thread). It does so by managing the NSOpenGLContext explicitly rather than using NSOpenGLView to do it for us.

This commit is contained in:
Steve Checkoway
2006-01-17 06:10:33 +00:00
parent 45d3dff2d6
commit ec789f1473
2 changed files with 56 additions and 20 deletions
@@ -14,7 +14,7 @@ class LowLevelWindow_Cocoa : public LowLevelWindow
{ {
VideoModeParams mCurrentParams; VideoModeParams mCurrentParams;
id mWindow; id mWindow;
id mView; id mWindowContext;
id mFullScreenContext; id mFullScreenContext;
bool mSharingContexts; bool mSharingContexts;
CFDictionaryRef mCurrentDisplayMode; CFDictionaryRef mCurrentDisplayMode;
@@ -26,6 +26,7 @@ public:
CString TryVideoMode( const VideoModeParams& p, bool& newDeviceOut ); CString TryVideoMode( const VideoModeParams& p, bool& newDeviceOut );
void GetDisplayResolutions( DisplayResolutions &dr ) const; void GetDisplayResolutions( DisplayResolutions &dr ) const;
void SwapBuffers(); void SwapBuffers();
void Update();
VideoModeParams GetActualVideoModeParams() const { return mCurrentParams; } VideoModeParams GetActualVideoModeParams() const { return mCurrentParams; }
private: private:
@@ -3,6 +3,7 @@
#import "DisplayResolutions.h" #import "DisplayResolutions.h"
#import "RageLog.h" #import "RageLog.h"
#import "RageUtil.h" #import "RageUtil.h"
#import "RageThreads.h"
#import "arch/ArchHooks/ArchHooks.h" #import "arch/ArchHooks/ArchHooks.h"
#import "archutils/Darwin/SMMainThread.h" #import "archutils/Darwin/SMMainThread.h"
@@ -10,7 +11,12 @@
#import <OpenGl/OpenGl.h> #import <OpenGl/OpenGl.h>
#import <mach-o/dyld.h> #import <mach-o/dyld.h>
static const int g_iStyleMask = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask; static const unsigned int g_iStyleMask = NSTitledWindowMask | NSClosableWindowMask |
NSMiniaturizableWindowMask | NSResizableWindowMask;
static bool g_bResized;
static int g_iWidth;
static int g_iHeight;
static RageMutex g_ResizeLock( "Window resize lock." );
// Simple helper class // Simple helper class
class AutoreleasePool class AutoreleasePool
@@ -32,6 +38,7 @@ public:
- (void) windowDidBecomeKey:(NSNotification *)aNotification; - (void) windowDidBecomeKey:(NSNotification *)aNotification;
- (void) windowDidResignKey:(NSNotification *)aNotification; - (void) windowDidResignKey:(NSNotification *)aNotification;
- (void) windowWillClose:(NSNotification *)aNotification; - (void) windowWillClose:(NSNotification *)aNotification;
- (void) windowDidResize:(NSNotification *)aNotification;
// XXX maybe use whichever screen contains the window? Hard for me to test though. // XXX maybe use whichever screen contains the window? Hard for me to test though.
//- (void) windowDidChangeScreen:(NSNotification *)aNotification; //- (void) windowDidChangeScreen:(NSNotification *)aNotification;
@end @end
@@ -51,9 +58,21 @@ public:
{ {
ArchHooks::SetUserQuit(); ArchHooks::SetUserQuit();
} }
- (void) windowDidResize:(NSNotification *)aNotification
{
id window = [aNotification object];
NSSize size = [NSWindow contentRectForFrameRect:[window frame] styleMask:g_iStyleMask].size;
LockMut( g_ResizeLock );
g_bResized = true;
g_iWidth = int( size.width );
g_iHeight = int( size.height );
}
@end @end
LowLevelWindow_Cocoa::LowLevelWindow_Cocoa() : mView(nil), mFullScreenContext(nil), mCurrentDisplayMode(NULL) LowLevelWindow_Cocoa::LowLevelWindow_Cocoa() : mWindowContext(nil), mFullScreenContext(nil), mCurrentDisplayMode(NULL)
{ {
POOL; POOL;
NSRect rect = { {0, 0}, {0, 0} }; NSRect rect = { {0, 0}, {0, 0} };
@@ -61,9 +80,8 @@ LowLevelWindow_Cocoa::LowLevelWindow_Cocoa() : mView(nil), mFullScreenContext(ni
mWindow = [[NSWindow alloc] initWithContentRect:rect mWindow = [[NSWindow alloc] initWithContentRect:rect
styleMask:g_iStyleMask styleMask:g_iStyleMask
backing:NSBackingStoreNonretained backing:NSBackingStoreBuffered
defer:YES]; defer:YES];
ASSERT( mWindow != nil );
ADD_ACTIONb( mt, mWindow, setExcludedFromWindowsMenu:, YES ); ADD_ACTIONb( mt, mWindow, setExcludedFromWindowsMenu:, YES );
ADD_ACTIONb( mt, mWindow, useOptimizedDrawing:, YES ); ADD_ACTIONb( mt, mWindow, useOptimizedDrawing:, YES );
@@ -90,9 +108,11 @@ LowLevelWindow_Cocoa::~LowLevelWindow_Cocoa()
ADD_ACTION1( mt, mWindow, orderOut:, nil ); ADD_ACTION1( mt, mWindow, orderOut:, nil );
ADD_ACTION0( mt, mWindow, release ); ADD_ACTION0( mt, mWindow, release );
[mWindowContext clearDrawable];
[mt performOnMainThread]; [mt performOnMainThread];
[delegate release]; [delegate release];
[mt release]; [mt release];
[mWindowContext release];
[mFullScreenContext release]; [mFullScreenContext release];
} }
@@ -148,7 +168,7 @@ CString LowLevelWindow_Cocoa::TryVideoMode( const VideoModeParams& p, bool& newD
ASSERT( p.bpp == 16 || p.bpp == 32 ); ASSERT( p.bpp == 16 || p.bpp == 32 );
if( p.bpp != mCurrentParams.bpp || !mView ) if( p.bpp != mCurrentParams.bpp || !mWindowContext )
{ {
NSOpenGLPixelFormat *pixelFormat; NSOpenGLPixelFormat *pixelFormat;
NSOpenGLPixelFormatAttribute attrs[] = { NSOpenGLPixelFormatAttribute attrs[] = {
@@ -159,7 +179,6 @@ CString LowLevelWindow_Cocoa::TryVideoMode( const VideoModeParams& p, bool& newD
NSOpenGLPFAColorSize, NSOpenGLPixelFormatAttribute(p.bpp == 16 ? 16 : 24), NSOpenGLPFAColorSize, NSOpenGLPixelFormatAttribute(p.bpp == 16 ? 16 : 24),
NSOpenGLPixelFormatAttribute(0) NSOpenGLPixelFormatAttribute(0)
}; };
id nextView;
pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs]; pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
@@ -168,36 +187,37 @@ CString LowLevelWindow_Cocoa::TryVideoMode( const VideoModeParams& p, bool& newD
[mt performOnMainThread]; [mt performOnMainThread];
return "Failed to set the windowed pixel format."; return "Failed to set the windowed pixel format.";
} }
nextView = [[[NSOpenGLView alloc] initWithFrame:contentRect pixelFormat:pixelFormat] autorelease]; id nextContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:nil];
[pixelFormat release]; [pixelFormat release];
if( nextView == nil ) if( nextContext == nil )
{ {
[mt performOnMainThread]; [mt performOnMainThread];
return "Failed to create windowed OGL context."; return "Failed to create windowed OGL context.";
} }
SetOGLParameters( [mView openGLContext] ); SetOGLParameters( nextContext );
newDeviceOut = true; newDeviceOut = true;
mView = nextView; [mWindowContext clearDrawable];
ADD_ACTION1( mt, mWindow, setContentView:, mView ); [mWindowContext release];
mWindowContext = nextContext;
// We need to recreate the full screen context as well. // We need to recreate the full screen context as well.
[mFullScreenContext clearDrawable]; [mFullScreenContext clearDrawable];
[mFullScreenContext release]; [mFullScreenContext release];
mFullScreenContext = nil; mFullScreenContext = nil;
mCurrentParams.bpp = p.bpp; mCurrentParams.bpp = p.bpp;
mSharingContexts = false;
} }
if( p.windowed ) if( p.windowed )
{ {
id context = [mView openGLContext];
ShutDownFullScreen(); ShutDownFullScreen();
ADD_ACTION0( mt, mWindow, center ); ADD_ACTION0( mt, mWindow, center );
ADD_ACTION1( mt, mWindow, makeKeyAndOrderFront:, nil ); ADD_ACTION1( mt, mWindow, makeKeyAndOrderFront:, nil );
[mt performOnMainThread]; [mt performOnMainThread];
[context update]; [mWindowContext setView:[mWindow contentView]];
[context makeCurrentContext]; [mWindowContext update];
[mWindowContext makeCurrentContext];
mCurrentParams.windowed = true; mCurrentParams.windowed = true;
SetActualParamsFromMode( CGDisplayCurrentMode(kCGDirectMainDisplay) ); SetActualParamsFromMode( CGDisplayCurrentMode(kCGDirectMainDisplay) );
@@ -236,8 +256,7 @@ CString LowLevelWindow_Cocoa::TryVideoMode( const VideoModeParams& p, bool& newD
return "Failed to set full screen pixel format."; return "Failed to set full screen pixel format.";
} }
mFullScreenContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat mFullScreenContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:mWindowContext];
shareContext:[mView openGLContext]];
if( !(mSharingContexts = mFullScreenContext != nil) ) if( !(mSharingContexts = mFullScreenContext != nil) )
{ {
LOG->Warn( "Failed to share openGL contexts." ); LOG->Warn( "Failed to share openGL contexts." );
@@ -371,5 +390,21 @@ void LowLevelWindow_Cocoa::GetDisplayResolutions( DisplayResolutions &dr ) const
void LowLevelWindow_Cocoa::SwapBuffers() void LowLevelWindow_Cocoa::SwapBuffers()
{ {
[[NSOpenGLContext currentContext] flushBuffer]; [(mCurrentParams.windowed ? mWindowContext : mFullScreenContext) flushBuffer];
}
void LowLevelWindow_Cocoa::Update()
{
LockMutex lock( g_ResizeLock );
if( likely(!g_bResized) )
return;
LOG->Trace( "LLW_Cocoa::Update(): %d x %d", mCurrentParams.width, mCurrentParams.height );
if( mCurrentParams.width == g_iWidth && mCurrentParams.height == g_iHeight )
return;
mCurrentParams.width = g_iWidth;
mCurrentParams.height = g_iHeight;
g_bResized = false;
lock.Unlock(); // Unlock before calling ResolutionChanged().
[mWindowContext update];
DISPLAY->ResolutionChanged();
} }