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;
id mWindow;
id mView;
id mWindowContext;
id mFullScreenContext;
bool mSharingContexts;
CFDictionaryRef mCurrentDisplayMode;
@@ -26,6 +26,7 @@ public:
CString TryVideoMode( const VideoModeParams& p, bool& newDeviceOut );
void GetDisplayResolutions( DisplayResolutions &dr ) const;
void SwapBuffers();
void Update();
VideoModeParams GetActualVideoModeParams() const { return mCurrentParams; }
private:
@@ -3,6 +3,7 @@
#import "DisplayResolutions.h"
#import "RageLog.h"
#import "RageUtil.h"
#import "RageThreads.h"
#import "arch/ArchHooks/ArchHooks.h"
#import "archutils/Darwin/SMMainThread.h"
@@ -10,7 +11,12 @@
#import <OpenGl/OpenGl.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
class AutoreleasePool
@@ -32,6 +38,7 @@ public:
- (void) windowDidBecomeKey:(NSNotification *)aNotification;
- (void) windowDidResignKey:(NSNotification *)aNotification;
- (void) windowWillClose:(NSNotification *)aNotification;
- (void) windowDidResize:(NSNotification *)aNotification;
// XXX maybe use whichever screen contains the window? Hard for me to test though.
//- (void) windowDidChangeScreen:(NSNotification *)aNotification;
@end
@@ -51,9 +58,21 @@ public:
{
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
LowLevelWindow_Cocoa::LowLevelWindow_Cocoa() : mView(nil), mFullScreenContext(nil), mCurrentDisplayMode(NULL)
LowLevelWindow_Cocoa::LowLevelWindow_Cocoa() : mWindowContext(nil), mFullScreenContext(nil), mCurrentDisplayMode(NULL)
{
POOL;
NSRect rect = { {0, 0}, {0, 0} };
@@ -61,9 +80,8 @@ LowLevelWindow_Cocoa::LowLevelWindow_Cocoa() : mView(nil), mFullScreenContext(ni
mWindow = [[NSWindow alloc] initWithContentRect:rect
styleMask:g_iStyleMask
backing:NSBackingStoreNonretained
backing:NSBackingStoreBuffered
defer:YES];
ASSERT( mWindow != nil );
ADD_ACTIONb( mt, mWindow, setExcludedFromWindowsMenu:, YES );
ADD_ACTIONb( mt, mWindow, useOptimizedDrawing:, YES );
@@ -90,9 +108,11 @@ LowLevelWindow_Cocoa::~LowLevelWindow_Cocoa()
ADD_ACTION1( mt, mWindow, orderOut:, nil );
ADD_ACTION0( mt, mWindow, release );
[mWindowContext clearDrawable];
[mt performOnMainThread];
[delegate release];
[mt release];
[mWindowContext release];
[mFullScreenContext release];
}
@@ -148,7 +168,7 @@ CString LowLevelWindow_Cocoa::TryVideoMode( const VideoModeParams& p, bool& newD
ASSERT( p.bpp == 16 || p.bpp == 32 );
if( p.bpp != mCurrentParams.bpp || !mView )
if( p.bpp != mCurrentParams.bpp || !mWindowContext )
{
NSOpenGLPixelFormat *pixelFormat;
NSOpenGLPixelFormatAttribute attrs[] = {
@@ -159,7 +179,6 @@ CString LowLevelWindow_Cocoa::TryVideoMode( const VideoModeParams& p, bool& newD
NSOpenGLPFAColorSize, NSOpenGLPixelFormatAttribute(p.bpp == 16 ? 16 : 24),
NSOpenGLPixelFormatAttribute(0)
};
id nextView;
pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
@@ -168,36 +187,37 @@ CString LowLevelWindow_Cocoa::TryVideoMode( const VideoModeParams& p, bool& newD
[mt performOnMainThread];
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];
if( nextView == nil )
if( nextContext == nil )
{
[mt performOnMainThread];
return "Failed to create windowed OGL context.";
}
SetOGLParameters( [mView openGLContext] );
SetOGLParameters( nextContext );
newDeviceOut = true;
mView = nextView;
ADD_ACTION1( mt, mWindow, setContentView:, mView );
[mWindowContext clearDrawable];
[mWindowContext release];
mWindowContext = nextContext;
// We need to recreate the full screen context as well.
[mFullScreenContext clearDrawable];
[mFullScreenContext release];
mFullScreenContext = nil;
mCurrentParams.bpp = p.bpp;
mSharingContexts = false;
}
if( p.windowed )
{
id context = [mView openGLContext];
{
ShutDownFullScreen();
ADD_ACTION0( mt, mWindow, center );
ADD_ACTION1( mt, mWindow, makeKeyAndOrderFront:, nil );
[mt performOnMainThread];
[context update];
[context makeCurrentContext];
[mWindowContext setView:[mWindow contentView]];
[mWindowContext update];
[mWindowContext makeCurrentContext];
mCurrentParams.windowed = true;
SetActualParamsFromMode( CGDisplayCurrentMode(kCGDirectMainDisplay) );
@@ -236,8 +256,7 @@ CString LowLevelWindow_Cocoa::TryVideoMode( const VideoModeParams& p, bool& newD
return "Failed to set full screen pixel format.";
}
mFullScreenContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat
shareContext:[mView openGLContext]];
mFullScreenContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:mWindowContext];
if( !(mSharingContexts = mFullScreenContext != nil) )
{
LOG->Warn( "Failed to share openGL contexts." );
@@ -371,5 +390,21 @@ void LowLevelWindow_Cocoa::GetDisplayResolutions( DisplayResolutions &dr ) const
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();
}