Commit 3f3ee639 authored by Ken Thomases's avatar Ken Thomases Committed by Alexandre Julliard

winemac: Implement OpenGL support.

parent f18439da
MODULE = winemac.drv MODULE = winemac.drv
IMPORTS = user32 gdi32 advapi32 IMPORTS = user32 gdi32 advapi32
EXTRALIBS = -framework AppKit -framework Carbon -framework Security EXTRALIBS = -framework AppKit -framework Carbon -framework Security -framework OpenGL
C_SRCS = \ C_SRCS = \
display.c \ display.c \
...@@ -9,6 +9,7 @@ C_SRCS = \ ...@@ -9,6 +9,7 @@ C_SRCS = \
keyboard.c \ keyboard.c \
macdrv_main.c \ macdrv_main.c \
mouse.c \ mouse.c \
opengl.c \
scroll.c \ scroll.c \
surface.c \ surface.c \
window.c window.c
...@@ -18,6 +19,7 @@ OBJC_SRCS = \ ...@@ -18,6 +19,7 @@ OBJC_SRCS = \
cocoa_display.m \ cocoa_display.m \
cocoa_event.m \ cocoa_event.m \
cocoa_main.m \ cocoa_main.m \
cocoa_opengl.m \
cocoa_window.m cocoa_window.m
@MAKE_DLL_RULES@ @MAKE_DLL_RULES@
/*
* MACDRV Cocoa OpenGL declarations
*
* Copyright 2012, 2013 Ken Thomases for CodeWeavers Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#import <AppKit/AppKit.h>
@interface WineOpenGLContext : NSOpenGLContext
{
NSView* latentView;
BOOL needsUpdate;
}
@property BOOL needsUpdate;
@end
/*
* MACDRV Cocoa OpenGL code
*
* Copyright 2012, 2013 Ken Thomases for CodeWeavers Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#import "cocoa_opengl.h"
#include "macdrv_cocoa.h"
@interface WineOpenGLContext ()
@property (retain, nonatomic) NSView* latentView;
@end
@implementation WineOpenGLContext
@synthesize latentView, needsUpdate;
- (void) dealloc
{
[latentView release];
[super dealloc];
}
@end
/***********************************************************************
* macdrv_create_opengl_context
*
* Returns a Cocoa OpenGL context created from a CoreGL context. The
* caller is responsible for calling macdrv_dispose_opengl_context()
* when done with the context object.
*/
macdrv_opengl_context macdrv_create_opengl_context(void* cglctx)
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
WineOpenGLContext *context;
context = [[WineOpenGLContext alloc] initWithCGLContextObj:cglctx];
[pool release];
return (macdrv_opengl_context)context;
}
/***********************************************************************
* macdrv_dispose_opengl_context
*
* Destroys a Cocoa OpenGL context previously created by
* macdrv_create_opengl_context();
*/
void macdrv_dispose_opengl_context(macdrv_opengl_context c)
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
WineOpenGLContext *context = (WineOpenGLContext*)c;
if ([context view])
macdrv_remove_view_opengl_context((macdrv_view)[context view], c);
if ([context latentView])
macdrv_remove_view_opengl_context((macdrv_view)[context latentView], c);
[context clearDrawable];
[context release];
[pool release];
}
/***********************************************************************
* macdrv_make_context_current
*/
void macdrv_make_context_current(macdrv_opengl_context c, macdrv_view v)
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
WineOpenGLContext *context = (WineOpenGLContext*)c;
NSView* view = (NSView*)v;
if (context)
{
if ([context view])
macdrv_remove_view_opengl_context((macdrv_view)[context view], c);
if ([context latentView])
macdrv_remove_view_opengl_context((macdrv_view)[context latentView], c);
context.needsUpdate = FALSE;
if (view)
{
macdrv_add_view_opengl_context(v, c);
[context setLatentView:view];
[context makeCurrentContext];
}
else
{
[WineOpenGLContext clearCurrentContext];
[context clearDrawable];
}
}
else
[WineOpenGLContext clearCurrentContext];
[pool release];
}
/***********************************************************************
* macdrv_update_opengl_context
*/
void macdrv_update_opengl_context(macdrv_opengl_context c)
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
WineOpenGLContext *context = (WineOpenGLContext*)c;
if (context.needsUpdate)
{
context.needsUpdate = FALSE;
if (context.latentView)
{
[context setView:context.latentView];
context.latentView = nil;
}
else
[context update];
}
[pool release];
}
/***********************************************************************
* macdrv_flush_opengl_context
*
* Performs an implicit glFlush() and then swaps the back buffer to the
* front (if the context is double-buffered).
*/
void macdrv_flush_opengl_context(macdrv_opengl_context c)
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
WineOpenGLContext *context = (WineOpenGLContext*)c;
macdrv_update_opengl_context(c);
[context flushBuffer];
[pool release];
}
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "macdrv_cocoa.h" #include "macdrv_cocoa.h"
#import "cocoa_app.h" #import "cocoa_app.h"
#import "cocoa_event.h" #import "cocoa_event.h"
#import "cocoa_opengl.h"
/* Additional Mac virtual keycode, to complement those in Carbon's <HIToolbox/Events.h>. */ /* Additional Mac virtual keycode, to complement those in Carbon's <HIToolbox/Events.h>. */
...@@ -118,6 +119,15 @@ static inline void fix_generic_modifiers_by_device(NSUInteger* modifiers) ...@@ -118,6 +119,15 @@ static inline void fix_generic_modifiers_by_device(NSUInteger* modifiers)
@interface WineContentView : NSView @interface WineContentView : NSView
{
NSMutableArray* glContexts;
NSMutableArray* pendingGlContexts;
}
- (void) addGLContext:(WineOpenGLContext*)context;
- (void) removeGLContext:(WineOpenGLContext*)context;
- (void) updateGLContexts;
@end @end
...@@ -149,6 +159,13 @@ static inline void fix_generic_modifiers_by_device(NSUInteger* modifiers) ...@@ -149,6 +159,13 @@ static inline void fix_generic_modifiers_by_device(NSUInteger* modifiers)
@implementation WineContentView @implementation WineContentView
- (void) dealloc
{
[glContexts release];
[pendingGlContexts release];
[super dealloc];
}
- (BOOL) isFlipped - (BOOL) isFlipped
{ {
return YES; return YES;
...@@ -158,6 +175,14 @@ static inline void fix_generic_modifiers_by_device(NSUInteger* modifiers) ...@@ -158,6 +175,14 @@ static inline void fix_generic_modifiers_by_device(NSUInteger* modifiers)
{ {
WineWindow* window = (WineWindow*)[self window]; WineWindow* window = (WineWindow*)[self window];
for (WineOpenGLContext* context in pendingGlContexts)
context.needsUpdate = TRUE;
[glContexts addObjectsFromArray:pendingGlContexts];
[pendingGlContexts removeAllObjects];
if ([window contentView] != self)
return;
if (window.surface && window.surface_mutex && if (window.surface && window.surface_mutex &&
!pthread_mutex_lock(window.surface_mutex)) !pthread_mutex_lock(window.surface_mutex))
{ {
...@@ -227,6 +252,28 @@ static inline void fix_generic_modifiers_by_device(NSUInteger* modifiers) ...@@ -227,6 +252,28 @@ static inline void fix_generic_modifiers_by_device(NSUInteger* modifiers)
[[self window] rightMouseDown:theEvent]; [[self window] rightMouseDown:theEvent];
} }
- (void) addGLContext:(WineOpenGLContext*)context
{
if (!glContexts)
glContexts = [[NSMutableArray alloc] init];
if (!pendingGlContexts)
pendingGlContexts = [[NSMutableArray alloc] init];
[pendingGlContexts addObject:context];
[self setNeedsDisplay:YES];
}
- (void) removeGLContext:(WineOpenGLContext*)context
{
[glContexts removeObjectIdenticalTo:context];
[pendingGlContexts removeObjectIdenticalTo:context];
}
- (void) updateGLContexts
{
for (WineOpenGLContext* context in glContexts)
context.needsUpdate = TRUE;
}
- (BOOL) acceptsFirstMouse:(NSEvent*)theEvent - (BOOL) acceptsFirstMouse:(NSEvent*)theEvent
{ {
return YES; return YES;
...@@ -1470,3 +1517,143 @@ void macdrv_give_cocoa_window_focus(macdrv_window w) ...@@ -1470,3 +1517,143 @@ void macdrv_give_cocoa_window_focus(macdrv_window w)
[window makeFocused]; [window makeFocused];
}); });
} }
/***********************************************************************
* macdrv_create_view
*
* Creates and returns a view in the specified rect of the window. The
* caller is responsible for calling macdrv_dispose_view() on the view
* when it is done with it.
*/
macdrv_view macdrv_create_view(macdrv_window w, CGRect rect)
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
WineWindow* window = (WineWindow*)w;
__block WineContentView* view;
if (CGRectIsNull(rect)) rect = CGRectZero;
OnMainThread(^{
NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
view = [[WineContentView alloc] initWithFrame:NSRectFromCGRect(rect)];
[view setAutoresizesSubviews:NO];
[nc addObserver:view
selector:@selector(updateGLContexts)
name:NSViewGlobalFrameDidChangeNotification
object:view];
[nc addObserver:view
selector:@selector(updateGLContexts)
name:NSApplicationDidChangeScreenParametersNotification
object:NSApp];
[[window contentView] addSubview:view];
});
[pool release];
return (macdrv_view)view;
}
/***********************************************************************
* macdrv_dispose_view
*
* Destroys a view previously returned by macdrv_create_view.
*/
void macdrv_dispose_view(macdrv_view v)
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
WineContentView* view = (WineContentView*)v;
OnMainThread(^{
NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
[nc removeObserver:view
name:NSViewGlobalFrameDidChangeNotification
object:view];
[nc removeObserver:view
name:NSApplicationDidChangeScreenParametersNotification
object:NSApp];
[view removeFromSuperview];
[view release];
});
[pool release];
}
/***********************************************************************
* macdrv_set_view_window_and_frame
*
* Move a view to a new window and/or position within its window. If w
* is NULL, leave the view in its current window and just change its
* frame.
*/
void macdrv_set_view_window_and_frame(macdrv_view v, macdrv_window w, CGRect rect)
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
WineContentView* view = (WineContentView*)v;
WineWindow* window = (WineWindow*)w;
if (CGRectIsNull(rect)) rect = CGRectZero;
OnMainThread(^{
BOOL changedWindow = (window && window != [view window]);
NSRect newFrame = NSRectFromCGRect(rect);
NSRect oldFrame = [view frame];
if (changedWindow)
{
[view removeFromSuperview];
[[window contentView] addSubview:view];
}
if (!NSEqualRects(oldFrame, newFrame))
{
if (!changedWindow)
[[view superview] setNeedsDisplayInRect:oldFrame];
if (NSEqualPoints(oldFrame.origin, newFrame.origin))
[view setFrameSize:newFrame.size];
else if (NSEqualSizes(oldFrame.size, newFrame.size))
[view setFrameOrigin:newFrame.origin];
else
[view setFrame:newFrame];
[view setNeedsDisplay:YES];
}
});
[pool release];
}
/***********************************************************************
* macdrv_add_view_opengl_context
*
* Add an OpenGL context to the list being tracked for each view.
*/
void macdrv_add_view_opengl_context(macdrv_view v, macdrv_opengl_context c)
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
WineContentView* view = (WineContentView*)v;
WineOpenGLContext *context = (WineOpenGLContext*)c;
OnMainThreadAsync(^{
[view addGLContext:context];
});
[pool release];
}
/***********************************************************************
* macdrv_remove_view_opengl_context
*
* Add an OpenGL context to the list being tracked for each view.
*/
void macdrv_remove_view_opengl_context(macdrv_view v, macdrv_opengl_context c)
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
WineContentView* view = (WineContentView*)v;
WineOpenGLContext *context = (WineOpenGLContext*)c;
OnMainThreadAsync(^{
[view removeGLContext:context];
});
[pool release];
}
...@@ -548,7 +548,7 @@ static const struct gdi_dc_funcs macdrv_funcs = ...@@ -548,7 +548,7 @@ static const struct gdi_dc_funcs macdrv_funcs =
NULL, /* pStrokePath */ NULL, /* pStrokePath */
NULL, /* pUnrealizePalette */ NULL, /* pUnrealizePalette */
NULL, /* pWidenPath */ NULL, /* pWidenPath */
NULL, /* wine_get_wgl_driver */ macdrv_wine_get_wgl_driver, /* wine_get_wgl_driver */
GDI_PRIORITY_GRAPHICS_DRV /* priority */ GDI_PRIORITY_GRAPHICS_DRV /* priority */
}; };
......
...@@ -118,6 +118,9 @@ struct macdrv_win_data ...@@ -118,6 +118,9 @@ struct macdrv_win_data
RECT window_rect; /* USER window rectangle relative to parent */ RECT window_rect; /* USER window rectangle relative to parent */
RECT whole_rect; /* Mac window rectangle for the whole window relative to parent */ RECT whole_rect; /* Mac window rectangle for the whole window relative to parent */
RECT client_rect; /* client area relative to parent */ RECT client_rect; /* client area relative to parent */
int pixel_format; /* pixel format for GL */
macdrv_view gl_view; /* view for GL */
RECT gl_rect; /* GL view rectangle relative to whole_rect */
COLORREF color_key; /* color key for layered window; CLR_INVALID is not color keyed */ COLORREF color_key; /* color key for layered window; CLR_INVALID is not color keyed */
BOOL on_screen : 1; /* is window ordered in? (minimized or not) */ BOOL on_screen : 1; /* is window ordered in? (minimized or not) */
BOOL shaped : 1; /* is window using a custom region shape? */ BOOL shaped : 1; /* is window using a custom region shape? */
...@@ -127,6 +130,9 @@ struct macdrv_win_data ...@@ -127,6 +130,9 @@ struct macdrv_win_data
struct window_surface *surface; struct window_surface *surface;
}; };
extern struct macdrv_win_data *get_win_data(HWND hwnd) DECLSPEC_HIDDEN;
extern void release_win_data(struct macdrv_win_data *data) DECLSPEC_HIDDEN;
extern macdrv_window macdrv_get_cocoa_window(HWND hwnd, BOOL require_on_screen) DECLSPEC_HIDDEN;
extern RGNDATA *get_region_data(HRGN hrgn, HDC hdc_lptodp) DECLSPEC_HIDDEN; extern RGNDATA *get_region_data(HRGN hrgn, HDC hdc_lptodp) DECLSPEC_HIDDEN;
extern struct window_surface *create_surface(macdrv_window window, const RECT *rect, BOOL use_alpha) DECLSPEC_HIDDEN; extern struct window_surface *create_surface(macdrv_window window, const RECT *rect, BOOL use_alpha) DECLSPEC_HIDDEN;
extern void set_window_surface(macdrv_window window, struct window_surface *window_surface) DECLSPEC_HIDDEN; extern void set_window_surface(macdrv_window window, struct window_surface *window_surface) DECLSPEC_HIDDEN;
...@@ -150,4 +156,8 @@ extern void macdrv_key_event(HWND hwnd, const macdrv_event *event) DECLSPEC_HIDD ...@@ -150,4 +156,8 @@ extern void macdrv_key_event(HWND hwnd, const macdrv_event *event) DECLSPEC_HIDD
extern void macdrv_displays_changed(const macdrv_event *event) DECLSPEC_HIDDEN; extern void macdrv_displays_changed(const macdrv_event *event) DECLSPEC_HIDDEN;
extern struct opengl_funcs *macdrv_wine_get_wgl_driver(PHYSDEV dev, UINT version) DECLSPEC_HIDDEN;
extern void sync_gl_view(struct macdrv_win_data *data) DECLSPEC_HIDDEN;
extern void set_gl_view_parent(HWND hwnd, HWND parent) DECLSPEC_HIDDEN;
#endif /* __WINE_MACDRV_H */ #endif /* __WINE_MACDRV_H */
...@@ -101,6 +101,8 @@ ...@@ -101,6 +101,8 @@
typedef struct macdrv_opaque_window* macdrv_window; typedef struct macdrv_opaque_window* macdrv_window;
typedef struct macdrv_opaque_event_queue* macdrv_event_queue; typedef struct macdrv_opaque_event_queue* macdrv_event_queue;
typedef struct macdrv_opaque_view* macdrv_view;
typedef struct macdrv_opaque_opengl_context* macdrv_opengl_context;
struct macdrv_event; struct macdrv_event;
struct macdrv_display { struct macdrv_display {
...@@ -260,9 +262,22 @@ extern void macdrv_set_window_color_key(macdrv_window w, CGFloat keyRed, CGFloat ...@@ -260,9 +262,22 @@ extern void macdrv_set_window_color_key(macdrv_window w, CGFloat keyRed, CGFloat
extern void macdrv_clear_window_color_key(macdrv_window w) DECLSPEC_HIDDEN; extern void macdrv_clear_window_color_key(macdrv_window w) DECLSPEC_HIDDEN;
extern void macdrv_window_use_per_pixel_alpha(macdrv_window w, int use_per_pixel_alpha) DECLSPEC_HIDDEN; extern void macdrv_window_use_per_pixel_alpha(macdrv_window w, int use_per_pixel_alpha) DECLSPEC_HIDDEN;
extern void macdrv_give_cocoa_window_focus(macdrv_window w) DECLSPEC_HIDDEN; extern void macdrv_give_cocoa_window_focus(macdrv_window w) DECLSPEC_HIDDEN;
extern macdrv_view macdrv_create_view(macdrv_window w, CGRect rect) DECLSPEC_HIDDEN;
extern void macdrv_dispose_view(macdrv_view v) DECLSPEC_HIDDEN;
extern void macdrv_set_view_window_and_frame(macdrv_view v, macdrv_window w, CGRect rect) DECLSPEC_HIDDEN;
extern void macdrv_add_view_opengl_context(macdrv_view v, macdrv_opengl_context c) DECLSPEC_HIDDEN;
extern void macdrv_remove_view_opengl_context(macdrv_view v, macdrv_opengl_context c) DECLSPEC_HIDDEN;
/* keyboard */ /* keyboard */
extern CFDataRef macdrv_copy_keyboard_layout(CGEventSourceKeyboardType* keyboard_type, int* is_iso) DECLSPEC_HIDDEN; extern CFDataRef macdrv_copy_keyboard_layout(CGEventSourceKeyboardType* keyboard_type, int* is_iso) DECLSPEC_HIDDEN;
/* opengl */
extern macdrv_opengl_context macdrv_create_opengl_context(void* cglctx) DECLSPEC_HIDDEN;
extern void macdrv_dispose_opengl_context(macdrv_opengl_context c) DECLSPEC_HIDDEN;
extern void macdrv_make_context_current(macdrv_opengl_context c, macdrv_view v) DECLSPEC_HIDDEN;
extern void macdrv_update_opengl_context(macdrv_opengl_context c) DECLSPEC_HIDDEN;
extern void macdrv_flush_opengl_context(macdrv_opengl_context c) DECLSPEC_HIDDEN;
#endif /* __WINE_MACDRV_COCOA_H */ #endif /* __WINE_MACDRV_COCOA_H */
...@@ -245,7 +245,7 @@ static struct macdrv_win_data *alloc_win_data(HWND hwnd) ...@@ -245,7 +245,7 @@ static struct macdrv_win_data *alloc_win_data(HWND hwnd)
* *
* Lock and return the data structure associated with a window. * Lock and return the data structure associated with a window.
*/ */
static struct macdrv_win_data *get_win_data(HWND hwnd) struct macdrv_win_data *get_win_data(HWND hwnd)
{ {
struct macdrv_win_data *data; struct macdrv_win_data *data;
...@@ -263,7 +263,7 @@ static struct macdrv_win_data *get_win_data(HWND hwnd) ...@@ -263,7 +263,7 @@ static struct macdrv_win_data *get_win_data(HWND hwnd)
* *
* Release the data returned by get_win_data. * Release the data returned by get_win_data.
*/ */
static void release_win_data(struct macdrv_win_data *data) void release_win_data(struct macdrv_win_data *data)
{ {
if (data) LeaveCriticalSection(&win_data_section); if (data) LeaveCriticalSection(&win_data_section);
} }
...@@ -274,7 +274,7 @@ static void release_win_data(struct macdrv_win_data *data) ...@@ -274,7 +274,7 @@ static void release_win_data(struct macdrv_win_data *data)
* *
* Return the Mac window associated with the full area of a window * Return the Mac window associated with the full area of a window
*/ */
static macdrv_window macdrv_get_cocoa_window(HWND hwnd, BOOL require_on_screen) macdrv_window macdrv_get_cocoa_window(HWND hwnd, BOOL require_on_screen)
{ {
struct macdrv_win_data *data = get_win_data(hwnd); struct macdrv_win_data *data = get_win_data(hwnd);
macdrv_window ret = NULL; macdrv_window ret = NULL;
...@@ -826,6 +826,7 @@ void CDECL macdrv_DestroyWindow(HWND hwnd) ...@@ -826,6 +826,7 @@ void CDECL macdrv_DestroyWindow(HWND hwnd)
if (!(data = get_win_data(hwnd))) return; if (!(data = get_win_data(hwnd))) return;
if (data->gl_view) macdrv_dispose_view(data->gl_view);
destroy_cocoa_window(data); destroy_cocoa_window(data);
CFDictionaryRemoveValue(win_datas, hwnd); CFDictionaryRemoveValue(win_datas, hwnd);
...@@ -913,6 +914,8 @@ void CDECL macdrv_SetParent(HWND hwnd, HWND parent, HWND old_parent) ...@@ -913,6 +914,8 @@ void CDECL macdrv_SetParent(HWND hwnd, HWND parent, HWND old_parent)
else /* new top level window */ else /* new top level window */
create_cocoa_window(data); create_cocoa_window(data);
release_win_data(data); release_win_data(data);
set_gl_view_parent(hwnd, parent);
} }
...@@ -1360,6 +1363,8 @@ void CDECL macdrv_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags, ...@@ -1360,6 +1363,8 @@ void CDECL macdrv_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags,
} }
} }
sync_gl_view(data);
if (!data->cocoa_window) goto done; if (!data->cocoa_window) goto done;
if (data->on_screen) if (data->on_screen)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment