VirtualBox

source: vbox/trunk/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa_helper.m@ 27237

Last change on this file since 27237 was 25293, checked in by vboxsync, 15 years ago

crOpenGL-OSX: accidentally included to much into the timing update test

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 44.5 KB
Line 
1/** @file
2 *
3 * VirtualBox OpenGL Cocoa Window System Helper implementation
4 */
5
6/*
7 * Copyright (C) 2009 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22#include "renderspu_cocoa_helper.h"
23
24#include "chromium.h" /* For the visual bits of chromium */
25
26#include <iprt/thread.h>
27#include <iprt/string.h>
28
29/* Debug macros */
30#define FBO 1 /* Disable this to see how the output is without the FBO in the middle of the processing chain. */
31//#define SHOW_WINDOW_BACKGROUND 1 /* Define this to see the window background even if the window is clipped */
32//#define DEBUG_VERBOSE /* Define this could get some debug info about the messages flow. */
33
34#ifdef DEBUG_poetzsch
35#define DEBUG_MSG(text) \
36 printf text
37#else
38#define DEBUG_MSG(text) \
39 do {} while (0)
40#endif
41
42#ifdef DEBUG_VERBOSE
43#define DEBUG_MSG_1(text) \
44 DEBUG_MSG(text)
45#else
46#define DEBUG_MSG_1(text) \
47 do {} while (0)
48#endif
49
50#ifdef DEBUG_poetzsch
51#define CHECK_GL_ERROR()\
52 do \
53 { \
54 checkGLError(__FILE__, __LINE__); \
55 }while (0);
56
57 static void checkGLError(char *file, int line)
58 {
59 GLenum g = glGetError();
60 if (g != GL_NO_ERROR)
61 {
62 char *errStr;
63 switch (g)
64 {
65 case GL_INVALID_ENUM: errStr = RTStrDup("GL_INVALID_ENUM"); break;
66 case GL_INVALID_VALUE: errStr = RTStrDup("GL_INVALID_VALUE"); break;
67 case GL_INVALID_OPERATION: errStr = RTStrDup("GL_INVALID_OPERATION"); break;
68 case GL_STACK_OVERFLOW: errStr = RTStrDup("GL_STACK_OVERFLOW"); break;
69 case GL_STACK_UNDERFLOW: errStr = RTStrDup("GL_STACK_UNDERFLOW"); break;
70 case GL_OUT_OF_MEMORY: errStr = RTStrDup("GL_OUT_OF_MEMORY"); break;
71 case GL_TABLE_TOO_LARGE: errStr = RTStrDup("GL_TABLE_TOO_LARGE"); break;
72 default: errStr = RTStrDup("UNKOWN"); break;
73 }
74 DEBUG_MSG(("%s:%d: glError %d (%s)\n", file, line, g, errStr));
75 RTMemFree(errStr);
76 }
77 }
78#else
79#define CHECK_GL_ERROR()\
80 do {} while (0)
81#endif
82
83#define GL_SAVE_STATE \
84do \
85{ \
86 glPushAttrib(GL_ALL_ATTRIB_BITS); \
87 glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS); \
88 glMatrixMode(GL_PROJECTION); \
89 glPushMatrix(); \
90 glMatrixMode(GL_TEXTURE); \
91 glPushMatrix(); \
92 glMatrixMode(GL_COLOR); \
93 glPushMatrix(); \
94 glMatrixMode(GL_MODELVIEW); \
95 glPushMatrix(); \
96} \
97while(0);
98
99#define GL_RESTORE_STATE \
100do \
101{ \
102 glMatrixMode(GL_MODELVIEW); \
103 glPopMatrix(); \
104 glMatrixMode(GL_COLOR); \
105 glPopMatrix(); \
106 glMatrixMode(GL_TEXTURE); \
107 glPopMatrix(); \
108 glMatrixMode(GL_PROJECTION); \
109 glPopMatrix(); \
110 glPopClientAttrib(); \
111 glPopAttrib(); \
112} \
113while(0);
114
115/* Custom OpenGL context class. This implementation doesn't allow to set a view
116 * to the context, but save the view for later use. Also it saves a copy of the
117 * pixel format used to create that context for later use. */
118@interface OverlayOpenGLContext: NSOpenGLContext
119{
120@private
121 NSOpenGLPixelFormat *m_pPixelFormat;
122 NSView *m_pView;
123}
124- (NSOpenGLPixelFormat*)openGLPixelFormat;
125@end
126
127@class DockOverlayView;
128
129/* The custom view class. This is the main class of the cocoa OpenGL
130 * implementation. It manages an frame buffer object for the rendering of the
131 * guest applications. The guest applications render in this frame buffer which
132 * is bind to an OpenGL texture. To display the guest content, an secondary
133 * shared OpenGL context of the main OpenGL context is created. The secondary
134 * context is marked as non opaque & the texture is displayed on an object
135 * which is composed out of the several visible region rectangles. */
136@interface OverlayView: NSView
137{
138@private
139 NSView *m_pParentView;
140
141 NSOpenGLContext *m_pGLCtx;
142 NSOpenGLContext *m_pSharedGLCtx;
143 RTTHREAD mThread;
144
145 /* FBO handling */
146 GLuint m_FBOId;
147 GLuint m_FBOTexId;
148 NSSize m_FBOTexSize;
149 GLuint m_FBODepthStencilPackedId;
150
151 /* The corresponding dock tile view of this OpenGL view & all helper
152 * members. */
153 DockOverlayView *m_DockTileView;
154 GLuint m_FBOThumbId;
155 GLuint m_FBOThumbTexId;
156 GLfloat m_FBOThumbScaleX;
157 GLfloat m_FBOThumbScaleY;
158 uint64_t m_uiDockUpdateTime;
159
160 /* For clipping */
161 GLint m_cClipRects;
162 GLint *m_paClipRects;
163
164 /* Position/Size tracking */
165 NSPoint m_Pos;
166 NSSize m_Size;
167
168 /* This is necessary for clipping on the root window */
169 NSPoint m_RootShift;
170}
171- (id)initWithFrame:(NSRect)frame thread:(RTTHREAD)aThread parentView:(NSView*)pParentView;
172- (void)setGLCtx:(NSOpenGLContext*)pCtx;
173- (NSOpenGLContext*)glCtx;
174
175- (void)setPos:(NSPoint)pos;
176- (NSPoint)pos;
177- (void)setSize:(NSSize)size;
178- (NSSize)size;
179- (void)updateViewport;
180- (void)reshape;
181
182- (void)createFBO;
183- (void)deleteFBO;
184
185- (void)updateFBO;
186- (void)makeCurrentFBO;
187- (void)swapFBO;
188- (void)flushFBO;
189- (void)finishFBO;
190- (void)bindFBO;
191- (void)renderFBOToView;
192
193- (void)clearVisibleRegions;
194- (void)setVisibleRegions:(GLint)cRects paRects:(GLint*)paRects;
195
196- (NSView*)dockTileScreen;
197- (void)reshapeDockTile;
198@end
199
200/* Helper view. This view is added as a sub view of the parent view to track
201 * main window changes. Whenever the main window is changed (which happens on
202 * fullscreen/seamless entry/exit) the overlay window is informed & can add
203 * them self as a child window again. */
204@class OverlayWindow;
205@interface OverlayHelperView: NSView
206{
207@private
208 OverlayWindow *m_pOverlayWindow;
209}
210-(id)initWithOverlayWindow:(OverlayWindow*)pOverlayWindow;
211@end
212
213/* Custom window class. This is the overlay window which contains our custom
214 * NSView. Its a direct child of the Qt Main window. It marks its background
215 * transparent & non opaque to make clipping possible. It also disable mouse
216 * events and handle frame change events of the parent view. */
217@interface OverlayWindow: NSWindow
218{
219@private
220 NSView *m_pParentView;
221 OverlayView *m_pOverlayView;
222 OverlayHelperView *m_pOverlayHelperView;
223 NSThread *m_Thread;
224}
225- (id)initWithParentView:(NSView*)pParentView overlayView:(OverlayView*)pOverlayView;
226- (void)parentWindowFrameChanged:(NSNotification *)note;
227- (void)parentWindowChanged:(NSWindow*)pWindow;
228@end
229
230@interface DockOverlayView: NSView
231{
232 NSBitmapImageRep *m_ThumbBitmap;
233 NSImage *m_ThumbImage;
234 NSLock *m_Lock;
235}
236- (void)dealloc;
237- (void)cleanup;
238- (void)lock;
239- (void)unlock;
240- (void)setFrame:(NSRect)frame;
241- (void)drawRect:(NSRect)aRect;
242- (NSBitmapImageRep*)thumbBitmap;
243- (NSImage*)thumbImage;
244@end
245
246@implementation DockOverlayView
247- (id)init
248{
249 self = [super init];
250
251 if (self)
252 {
253 /* We need a lock cause the thumb image could be accessed from the main
254 * thread when someone is calling display on the dock tile & from the
255 * OpenGL thread when the thumbnail is updated. */
256 m_Lock = [[NSLock alloc] init];
257 }
258
259 return self;
260}
261
262- (void)dealloc
263{
264 [self cleanup];
265 [m_Lock release];
266
267 [super dealloc];
268}
269
270- (void)cleanup
271{
272 if (m_ThumbImage != nil)
273 {
274 [m_ThumbImage release];
275 m_ThumbImage = nil;
276 }
277 if (m_ThumbBitmap != nil)
278 {
279 [m_ThumbBitmap release];
280 m_ThumbBitmap = nil;
281 }
282}
283
284- (void)lock
285{
286 [m_Lock lock];
287}
288
289- (void)unlock
290{
291 [m_Lock unlock];
292}
293
294- (void)setFrame:(NSRect)frame
295{
296 [super setFrame:frame];
297
298 [self lock];
299 [self cleanup];
300
301 /* Create a buffer for our thumbnail image. Its in the size of this view. */
302 m_ThumbBitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
303 pixelsWide:frame.size.width
304 pixelsHigh:frame.size.height
305 bitsPerSample:8
306 samplesPerPixel:4
307 hasAlpha:YES
308 isPlanar:NO
309 colorSpaceName:NSDeviceRGBColorSpace
310 bytesPerRow:frame.size.width * 4
311 bitsPerPixel:8 * 4];
312 m_ThumbImage = [[NSImage alloc] initWithSize:[m_ThumbBitmap size]];
313 [m_ThumbImage addRepresentation:m_ThumbBitmap];
314 [self unlock];
315}
316
317- (BOOL)isFlipped
318{
319 return YES;
320}
321
322- (void)drawRect:(NSRect)aRect
323{
324 [self lock];
325#ifdef SHOW_WINDOW_BACKGROUND
326 [[NSColor colorWithCalibratedRed:1.0 green:0.0 blue:0.0 alpha:0.7] set];
327 NSRect frame = [self frame];
328 [NSBezierPath fillRect:NSMakeRect(0, 0, frame.size.width, frame.size.height)];
329#endif /* SHOW_WINDOW_BACKGROUND */
330 if (m_ThumbImage != nil)
331 [m_ThumbImage drawAtPoint:NSMakePoint(0, 0) fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
332 [self unlock];
333}
334
335- (NSBitmapImageRep*)thumbBitmap
336{
337 return m_ThumbBitmap;
338}
339
340- (NSImage*)thumbImage
341{
342 return m_ThumbImage;
343}
344@end
345
346/********************************************************************************
347*
348* OverlayOpenGLContext class implementation
349*
350********************************************************************************/
351@implementation OverlayOpenGLContext
352
353-(id)initWithFormat:(NSOpenGLPixelFormat*)format shareContext:(NSOpenGLContext*)share
354{
355 m_pPixelFormat = NULL;
356 m_pView = NULL;
357
358 self = [super initWithFormat:format shareContext:share];
359 if (self)
360 m_pPixelFormat = format;
361
362 return self;
363}
364
365- (void)dealloc
366{
367 DEBUG_MSG(("Dealloc context %X\n", (uint)self));
368
369 [m_pPixelFormat release];
370
371 [super dealloc];
372}
373
374-(bool)isDoubleBuffer
375{
376 GLint val;
377 [m_pPixelFormat getValues:&val forAttribute:NSOpenGLPFADoubleBuffer forVirtualScreen:0];
378 return val == GL_TRUE ? YES : NO;
379}
380
381-(void)setView:(NSView*)view
382{
383#ifdef FBO
384 m_pView = view;;
385#else
386 [super setView: view];
387#endif
388}
389
390-(NSView*)view
391{
392#ifdef FBO
393 return m_pView;
394#else
395 return [super view];
396#endif
397}
398
399-(void)clearDrawable
400{
401 m_pView = NULL;;
402 [super clearDrawable];
403}
404
405-(NSOpenGLPixelFormat*)openGLPixelFormat
406{
407 return m_pPixelFormat;
408}
409
410@end;
411
412/********************************************************************************
413*
414* OverlayHelperView class implementation
415*
416********************************************************************************/
417@implementation OverlayHelperView
418
419-(id)initWithOverlayWindow:(OverlayWindow*)pOverlayWindow
420{
421 self = [super initWithFrame:NSZeroRect];
422
423 m_pOverlayWindow = pOverlayWindow;
424
425 return self;
426}
427
428-(void)viewDidMoveToWindow
429{
430 [m_pOverlayWindow parentWindowChanged:[self window]];
431}
432
433@end
434
435/********************************************************************************
436*
437* OverlayWindow class implementation
438*
439********************************************************************************/
440@implementation OverlayWindow
441
442- (id)initWithParentView:(NSView*)pParentView overlayView:(OverlayView*)pOverlayView
443{
444 if(self = [super initWithContentRect:NSZeroRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO])
445 {
446 m_pParentView = pParentView;
447 m_pOverlayView = pOverlayView;
448 m_Thread = [NSThread currentThread];
449
450 m_pOverlayHelperView = [[OverlayHelperView alloc] initWithOverlayWindow:self];
451 /* Add the helper view as a child of the parent view to get notifications */
452 [pParentView addSubview:m_pOverlayHelperView];
453
454 /* Make sure this window is transparent */
455#ifdef SHOW_WINDOW_BACKGROUND
456 /* For debugging */
457 [self setBackgroundColor:[NSColor colorWithCalibratedRed:1.0 green:0.0 blue:0.0 alpha:0.7]];
458#else
459 [self setBackgroundColor:[NSColor clearColor]];
460#endif
461 [self setOpaque:NO];
462 [self setAlphaValue:.999];
463 /* Disable mouse events for this window */
464 [self setIgnoresMouseEvents:YES];
465
466 NSWindow *pParentWin = [m_pParentView window];
467
468 /* Initial set the position to the parents view top/left (Compiz fix). */
469 [self setFrameOrigin:
470 [pParentWin convertBaseToScreen:
471 [m_pParentView convertPoint:NSZeroPoint toView:nil]]];
472
473 /* Set the overlay view as our content view */
474 [self setContentView:m_pOverlayView];
475
476 /* Add ourself as a child to the parent views window. Note: this has to
477 * be done last so that everything else is setup in
478 * parentWindowChanged. */
479 [pParentWin addChildWindow:self ordered:NSWindowAbove];
480 }
481 return self;
482}
483
484- (void)dealloc
485{
486 DEBUG_MSG(("Dealloc window %X\n", (uint)self));
487
488 [[NSNotificationCenter defaultCenter] removeObserver:self];
489
490 [m_pOverlayHelperView removeFromSuperview];
491 [m_pOverlayHelperView release];
492
493 [super dealloc];
494}
495
496- (void)parentWindowFrameChanged:(NSNotification*)pNote
497{
498 /* Reposition this window with the help of the OverlayView. Perform the
499 * call in the OpenGL thread. */
500// [m_pOverlayView performSelector:@selector(reshape) onThread:m_Thread withObject:nil waitUntilDone:YES];
501 [m_pOverlayView reshape];
502}
503
504- (void)parentWindowChanged:(NSWindow*)pWindow
505{
506 [[NSNotificationCenter defaultCenter] removeObserver:self];
507 if(pWindow != nil)
508 {
509 /* Ask to get notifications when our parent window frame changes. */
510 [[NSNotificationCenter defaultCenter]
511 addObserver:self
512 selector:@selector(parentWindowFrameChanged:)
513 name:NSWindowDidResizeNotification
514 object:pWindow];
515 /* Add us self as child window */
516 [pWindow addChildWindow:self ordered:NSWindowAbove];
517 /* Reshape the overlay view after a short waiting time to let the main
518 * window resize itself properly. */
519// [m_pOverlayView performSelector:@selector(reshape) withObject:nil afterDelay:0.2];
520// [NSTimer scheduledTimerWithTimeInterval:0.2 target:m_pOverlayView selector:@selector(reshape) userInfo:nil repeats:NO];
521 [m_pOverlayView reshape];
522
523 }
524}
525
526@end
527
528/********************************************************************************
529*
530* OverlayView class implementation
531*
532********************************************************************************/
533@implementation OverlayView
534
535- (id)initWithFrame:(NSRect)frame thread:(RTTHREAD)aThread parentView:(NSView*)pParentView
536{
537 m_pParentView = pParentView;
538 /* Make some reasonable defaults */
539 m_pGLCtx = NULL;
540 m_pSharedGLCtx = NULL;
541 mThread = aThread;
542 m_FBOId = 0;
543 m_FBOTexId = 0;
544 m_FBOTexSize = NSZeroSize;
545 m_FBODepthStencilPackedId = 0;
546 m_cClipRects = 0;
547 m_paClipRects = NULL;
548 m_Pos = NSZeroPoint;
549 m_Size = NSZeroSize;
550 m_RootShift = NSZeroPoint;
551
552 DEBUG_MSG(("Init view %X (%X)\n", (uint)self, (uint)mThread));
553
554 self = [super initWithFrame:frame];
555
556 return self;
557}
558
559- (void)dealloc
560{
561 DEBUG_MSG(("Dealloc view %X\n", (uint)self));
562
563 [self deleteFBO];
564
565 if (m_pGLCtx)
566 {
567 if ([m_pGLCtx view] == self)
568 [m_pGLCtx clearDrawable];
569 }
570 if (m_pSharedGLCtx)
571 {
572 if ([m_pSharedGLCtx view] == self)
573 [m_pSharedGLCtx clearDrawable];
574
575 [m_pSharedGLCtx release];
576 }
577
578 [self clearVisibleRegions];
579
580 [super dealloc];
581}
582
583- (void)drawRect:(NSRect)aRect
584{
585// NSGraphicsContext*pC = [NSGraphicsContext currentContext];
586// [[NSColor blueColor] set];
587// NSBezierPath *p = [[NSBezierPath alloc] bezierPathWithOvalInRect:[self frame]];
588// [p fill];
589// [[NSColor greenColor] set];
590// [p stroke];
591// if ([self lockFocusIfCanDraw])
592// {
593// [self renderFBOToView];
594// [self unlockFocus];
595// }
596}
597
598- (void)setGLCtx:(NSOpenGLContext*)pCtx
599{
600 m_pGLCtx = pCtx;
601}
602
603- (NSOpenGLContext*)glCtx
604{
605 return m_pGLCtx;
606}
607
608- (void)setPos:(NSPoint)pos
609{
610 m_Pos = pos;
611 [self reshape];
612}
613
614- (NSPoint)pos
615{
616 return m_Pos;
617}
618
619- (void)setSize:(NSSize)size
620{
621 m_Size = size;
622 [self reshape];
623 [self updateFBO];
624}
625
626- (NSSize)size
627{
628 return m_Size;
629}
630
631- (void)updateViewport
632{
633 if (m_pSharedGLCtx)
634 {
635 /* Update the viewport for our OpenGL view */
636 [m_pSharedGLCtx makeCurrentContext];
637 [m_pSharedGLCtx update];
638
639 NSRect r = [self frame];
640 /* Setup all matrices */
641 glMatrixMode(GL_PROJECTION);
642 glLoadIdentity();
643 glViewport(0, 0, r.size.width, r.size.height);
644 glOrtho(0, r.size.width, 0, r.size.height, -1, 1);
645 glMatrixMode(GL_TEXTURE);
646 glLoadIdentity();
647 glTranslatef(0.0f, m_RootShift.y, 0.0f);
648 glMatrixMode(GL_MODELVIEW);
649 glLoadIdentity();
650 glTranslatef(-m_RootShift.x, 0.0f, 0.0f);
651
652 /* Clear background to transparent */
653 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
654
655 glEnable(GL_TEXTURE_RECTANGLE_ARB);
656 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_FBOTexId);
657
658 [m_pGLCtx makeCurrentContext];
659 }
660}
661
662- (void)reshape
663{
664 /* Getting the right screen coordinates of the parents frame is a little bit
665 * complicated. */
666 NSRect parentFrame = [m_pParentView frame];
667 NSPoint parentPos = [[m_pParentView window] convertBaseToScreen:[[m_pParentView superview] convertPointToBase:NSMakePoint(parentFrame.origin.x, parentFrame.origin.y + parentFrame.size.height)]];
668 parentFrame.origin.x = parentPos.x;
669 parentFrame.origin.y = parentPos.y;
670
671 /* Calculate the new screen coordinates of the overlay window. */
672 NSPoint childPos = NSMakePoint(m_Pos.x, m_Pos.y + m_Size.height);
673 childPos = [[m_pParentView window] convertBaseToScreen:[[m_pParentView superview] convertPointToBase:childPos]];
674
675 /* Make a frame out of it. */
676 NSRect childFrame = NSMakeRect(childPos.x, childPos.y, m_Size.width, m_Size.height);
677
678 /* We have to make sure that the overlay window will not be displayed out
679 * of the parent window. So intersect both frames & use the result as the new
680 * frame for the window. */
681 NSRect newFrame = NSIntersectionRect(parentFrame, childFrame);
682
683 /* Later we have to correct the texture position in the case the window is
684 * out of the parents window frame. So save the shift values for later use. */
685 if (parentFrame.origin.x > childFrame.origin.x)
686 m_RootShift.x = parentFrame.origin.x - childFrame.origin.x;
687 else
688 m_RootShift.x = 0;
689 if (parentFrame.origin.y > childFrame.origin.y)
690 m_RootShift.y = parentFrame.origin.y - childFrame.origin.y;
691 else
692 m_RootShift.y = 0;
693
694// NSScrollView *pScrollView = [[[m_pParentView window] contentView] enclosingScrollView];
695// if (pScrollView)
696// {
697// NSRect scrollRect = [pScrollView documentVisibleRect];
698// NSRect scrollRect = [m_pParentView visibleRect];
699// printf ("sc rect: %d %d %d %d\n", (int) scrollRect.origin.x,(int) scrollRect.origin.y,(int) scrollRect.size.width,(int) scrollRect.size.height);
700// NSRect b = [[m_pParentView superview] bounds];
701// printf ("bound rect: %d %d %d %d\n", (int) b.origin.x,(int) b.origin.y,(int) b.size.width,(int) b.size.height);
702// newFrame.origin.x += scrollRect.origin.x;
703// newFrame.origin.y += scrollRect.origin.y;
704// }
705
706 /* Set the new frame. */
707 [[self window] setFrame:newFrame display:YES];
708
709 /* Inform the dock tile view as well */
710 [self reshapeDockTile];
711
712 /* Make sure the context is updated according */
713 [self updateViewport];
714}
715
716- (void)createFBO
717{
718 [self deleteFBO];
719
720 GL_SAVE_STATE;
721
722 /* If not previously setup generate IDs for FBO and its associated texture. */
723 if (!m_FBOId)
724 {
725 /* Make sure the framebuffer extension is supported */
726 const GLubyte* strExt;
727 GLboolean isFBO;
728 /* Get the extension name string. It is a space-delimited list of the
729 * OpenGL extensions that are supported by the current renderer. */
730 strExt = glGetString(GL_EXTENSIONS);
731 isFBO = gluCheckExtension((const GLubyte*)"GL_EXT_framebuffer_object", strExt);
732 if (!isFBO)
733 {
734 DEBUG_MSG(("Your system does not support framebuffer extension\n"));
735 }
736
737 /* Create FBO object */
738 glGenFramebuffersEXT(1, &m_FBOId);
739 /* & the texture as well the depth/stencil render buffer */
740 glGenTextures(1, &m_FBOTexId);
741 DEBUG_MSG_1(("Create FBO %d %d\n", m_FBOId, m_FBOTexId));
742
743 glGenRenderbuffersEXT(1, &m_FBODepthStencilPackedId);
744 }
745
746 m_FBOTexSize = m_Size;
747 /* Bind to FBO */
748 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FBOId);
749
750 glEnable(GL_TEXTURE_RECTANGLE_ARB);
751
752 GLfloat imageAspectRatio = m_FBOTexSize.width / m_FBOTexSize.height;
753
754 /* Sanity check against maximum OpenGL texture size. If bigger adjust to
755 * maximum possible size while maintain the aspect ratio. */
756 GLint maxTexSize;
757 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize);
758// maxTexSize = 150;
759 GLint filter = GL_NEAREST;
760 if (m_FBOTexSize.width > maxTexSize || m_FBOTexSize.height > maxTexSize)
761 {
762 filter = GL_NICEST;
763 if (imageAspectRatio > 1)
764 {
765 m_FBOTexSize.width = maxTexSize;
766 m_FBOTexSize.height = maxTexSize / imageAspectRatio;
767 }
768 else
769 {
770 m_FBOTexSize.width = maxTexSize * imageAspectRatio;
771 m_FBOTexSize.height = maxTexSize;
772 }
773 }
774
775 /* Initialize FBO Texture */
776 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_FBOTexId);
777 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, filter);
778 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, filter);
779 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP);
780 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP);
781
782 /* The GPUs like the GL_BGRA / GL_UNSIGNED_INT_8_8_8_8_REV combination
783 * others are also valid, but might incur a costly software translation. */
784 glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, m_FBOTexSize.width, m_FBOTexSize.height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
785
786 /* Now attach texture to the FBO as its color destination */
787 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, m_FBOTexId, 0);
788
789 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_FBODepthStencilPackedId);
790 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_STENCIL_EXT, m_FBOTexSize.width, m_FBOTexSize.height);
791 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_FBODepthStencilPackedId);
792 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_FBODepthStencilPackedId);
793
794 /* Make sure the FBO was created succesfully. */
795 if (GL_FRAMEBUFFER_COMPLETE_EXT != glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT))
796 DEBUG_MSG(("Framebuffer Object creation or update failed!\n"));
797
798 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
799 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
800
801 /* Is there a dock tile preview enabled in the GUI? If so setup a
802 * additional thumbnail view for the dock tile. */
803 NSView *dockScreen = [self dockTileScreen];
804 if (dockScreen)
805 {
806 if (!m_FBOThumbId)
807 {
808 glGenFramebuffersEXT(1, &m_FBOThumbId);
809 glGenTextures(1, &m_FBOThumbTexId);
810 }
811
812 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FBOThumbId);
813 /* Initialize FBO Texture */
814 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_FBOThumbTexId);
815 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NICEST);
816 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NICEST);
817 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP);
818 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP);
819
820 /* The GPUs like the GL_BGRA / GL_UNSIGNED_INT_8_8_8_8_REV combination
821 * others are also valid, but might incur a costly software translation. */
822 glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, m_FBOTexSize.width * m_FBOThumbScaleX, m_FBOTexSize.height * m_FBOThumbScaleY, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
823
824 /* Now attach texture to the FBO as its color destination */
825 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, m_FBOThumbTexId, 0);
826
827 /* Make sure the FBO was created succesfully. */
828 if (GL_FRAMEBUFFER_COMPLETE_EXT != glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT))
829 DEBUG_MSG(("Framebuffer Thumb Object creation or update failed!\n"));
830
831 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
832 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
833
834 m_DockTileView = [[DockOverlayView alloc] init];
835 [self reshapeDockTile];
836 [dockScreen addSubview:m_DockTileView];
837 }
838
839 /* Initialize with one big visual region over the full size */
840 [self clearVisibleRegions];
841 m_cClipRects = 1;
842 m_paClipRects = (GLint*)RTMemAlloc(sizeof(GLint) * 4);
843 m_paClipRects[0] = 0;
844 m_paClipRects[1] = 0;
845 m_paClipRects[2] = m_FBOTexSize.width;
846 m_paClipRects[3] = m_FBOTexSize.height;
847
848 GL_RESTORE_STATE;
849}
850
851- (void)deleteFBO
852{
853 if ([NSOpenGLContext currentContext] != nil)
854 {
855 GL_SAVE_STATE;
856
857 if (m_FBODepthStencilPackedId > 0)
858 {
859 glDeleteRenderbuffersEXT(1, &m_FBODepthStencilPackedId);
860 m_FBODepthStencilPackedId = 0;
861 }
862 if (m_FBOTexId > 0)
863 {
864 glEnable(GL_TEXTURE_RECTANGLE_ARB);
865 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
866 glDeleteTextures(1, &m_FBOTexId);
867 m_FBOTexId = 0;
868 }
869 if (m_FBOId > 0)
870 {
871 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
872
873 glDeleteFramebuffersEXT(1, &m_FBOId);
874 m_FBOId = 0;
875 }
876
877 GL_RESTORE_STATE;
878 }
879 if (m_DockTileView != nil)
880 {
881 [m_DockTileView removeFromSuperview];
882 [m_DockTileView release];
883 m_DockTileView = nil;
884 }
885}
886
887- (void)updateFBO
888{
889 [self makeCurrentFBO];
890
891 if (m_pGLCtx)
892 {
893#ifdef FBO
894 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
895 [self createFBO];
896 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FBOId);
897#endif
898 [m_pGLCtx update];
899 }
900}
901
902- (void)makeCurrentFBO
903{
904 DEBUG_MSG_1(("MakeCurrent called %X\n", self));
905
906#ifdef FBO
907 if([NSOpenGLContext currentContext] != 0)
908 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FBOId);
909#endif
910 if (m_pGLCtx)
911 {
912 if ([m_pGLCtx view] != self)
913 {
914 /* We change the active view, so flush first */
915 if([NSOpenGLContext currentContext] != 0)
916 glFlush();
917 [m_pGLCtx setView: self];
918 CHECK_GL_ERROR();
919 }
920// if ([NSOpenGLContext currentContext] != m_pGLCtx)
921 {
922 [m_pGLCtx makeCurrentContext];
923 CHECK_GL_ERROR();
924// [m_pGLCtx update];
925 }
926 }
927#ifdef FBO
928 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FBOId);
929#endif
930}
931
932- (void)swapFBO
933{
934 DEBUG_MSG_1(("SwapCurrent called %X\n", self));
935
936#ifdef FBO
937 GLint tmpFB;
938 glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &tmpFB);
939 DEBUG_MSG_1(("Swap GetINT %d\n", tmpFB));
940 /* Don't use flush buffers cause we are using FBOs here */
941// [m_pGLCtx flushBuffer];
942 glFlush();
943// glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
944 if (tmpFB == m_FBOId)
945 {
946 if ([self lockFocusIfCanDraw])
947 {
948 [self renderFBOToView];
949 [self unlockFocus];
950 }
951 }
952// glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FBOId);
953#else
954 [m_pGLCtx flushBuffer];
955#endif
956}
957
958- (void)flushFBO
959{
960 GLint tmpFB;
961 glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &tmpFB);
962 glFlush();
963// glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
964 DEBUG_MSG_1 (("Flush GetINT %d\n", tmpFB));
965 if (tmpFB == m_FBOId)
966 {
967 if ([self lockFocusIfCanDraw])
968 {
969 [self renderFBOToView];
970 [self unlockFocus];
971 }
972 }
973// glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FBOId);
974}
975
976- (void)finishFBO
977{
978 GLint tmpFB;
979 glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &tmpFB);
980 glFinish();
981 // glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
982 DEBUG_MSG_1 (("Finish GetINT %d\n", tmpFB));
983 if (tmpFB == m_FBOId)
984 {
985 if ([self lockFocusIfCanDraw])
986 {
987 [self renderFBOToView];
988 [self unlockFocus];
989 }
990 }
991// glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FBOId);
992}
993
994- (void)bindFBO
995{
996 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FBOId);
997}
998
999- (void)renderFBOToView
1000{
1001 if (!m_pSharedGLCtx)
1002 {
1003 /* Create a shared context out of the main context. Use the same pixel format. */
1004 m_pSharedGLCtx = [[NSOpenGLContext alloc] initWithFormat:[(OverlayOpenGLContext*)m_pGLCtx openGLPixelFormat] shareContext:m_pGLCtx];
1005
1006 /* Set the new context as non opaque */
1007 GLint opaque = 0;
1008 [m_pSharedGLCtx setValues:&opaque forParameter:NSOpenGLCPSurfaceOpacity];
1009 /* Only swap on screen refresh */
1010// GLint swap = 1;
1011// [m_pSharedGLCtx setValues:&swap forParameter:NSOpenGLCPSwapInterval];
1012 /* Set this view as the drawable for the new context */
1013 [m_pSharedGLCtx setView: self];
1014 [self updateViewport];
1015 }
1016
1017 if (m_pSharedGLCtx)
1018 {
1019 NSRect r = [self frame];
1020
1021 if (m_FBOTexId > 0)
1022 {
1023 [m_pSharedGLCtx makeCurrentContext];
1024
1025 if (m_FBOThumbTexId > 0 &&
1026 [m_DockTileView thumbBitmap] != nil)
1027 {
1028 /* Only update after atleast 200 ms, cause glReadPixels is
1029 * heavy performance wise. */
1030 uint64_t uiNewTime = RTTimeMilliTS();
1031 if (uiNewTime - m_uiDockUpdateTime > 200)
1032 {
1033 m_uiDockUpdateTime = uiNewTime;
1034#if 0
1035 /* todo: check this for optimization */
1036 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, myTextureName);
1037 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_STORAGE_HINT_APPLE,
1038 GL_STORAGE_SHARED_APPLE);
1039 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1040 glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA,
1041 sizex, sizey, 0, GL_BGRA,
1042 GL_UNSIGNED_INT_8_8_8_8_REV, myImagePtr);
1043 glCopyTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB,
1044 0, 0, 0, 0, 0, image_width, image_height);
1045 glFlush();
1046 // Do other work processing here, using a double or triple buffer
1047 glGetTexImage(GL_TEXTURE_RECTANGLE_ARB, 0, GL_BGRA,
1048 GL_UNSIGNED_INT_8_8_8_8_REV, pixels);
1049#endif
1050
1051 GL_SAVE_STATE;
1052 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FBOThumbId);
1053
1054 /* We like to read from the primary color buffer */
1055 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
1056
1057 NSRect rr = [m_DockTileView frame];
1058
1059 /* Setup all matrices */
1060 glMatrixMode(GL_PROJECTION);
1061 glLoadIdentity();
1062 glViewport(0, 0, rr.size.width, rr.size.height);
1063 glOrtho(0, rr.size.width, 0, rr.size.height, -1, 1);
1064 glScalef(m_FBOThumbScaleX, m_FBOThumbScaleY, 1.0f);
1065 glMatrixMode(GL_TEXTURE);
1066 glLoadIdentity();
1067 glTranslatef(0.0f, m_RootShift.y, 0.0f);
1068 glMatrixMode(GL_MODELVIEW);
1069 glLoadIdentity();
1070
1071 /* Clear background to transparent */
1072 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
1073 glClear(GL_COLOR_BUFFER_BIT);
1074
1075 glEnable(GL_TEXTURE_RECTANGLE_ARB);
1076 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_FBOTexId);
1077 GLint i;
1078 for (i = 0; i < m_cClipRects; ++i)
1079 {
1080 GLint x1 = m_paClipRects[4*i];
1081 GLint y1 = (r.size.height - m_paClipRects[4*i+1]);
1082 GLint x2 = m_paClipRects[4*i+2];
1083 GLint y2 = (r.size.height - m_paClipRects[4*i+3]);
1084 glBegin(GL_QUADS);
1085 {
1086 glTexCoord2i(x1, y1); glVertex2i(x1, y1);
1087 glTexCoord2i(x1, y2); glVertex2i(x1, y2);
1088 glTexCoord2i(x2, y2); glVertex2i(x2, y2);
1089 glTexCoord2i(x2, y1); glVertex2i(x2, y1);
1090 }
1091 glEnd();
1092 }
1093 glFinish();
1094
1095 /* Here the magic of reading the FBO content in our own buffer
1096 * happens. We have to lock this access, in the case the dock
1097 * is updated currently. */
1098 [m_DockTileView lock];
1099 glReadPixels(0, 0, rr.size.width, rr.size.height,
1100 GL_RGBA,
1101 GL_UNSIGNED_BYTE,
1102 [[m_DockTileView thumbBitmap] bitmapData]);
1103 [m_DockTileView unlock];
1104
1105 NSDockTile *pDT = [[NSApplication sharedApplication] dockTile];
1106
1107 /* Send a display message to the dock tile in the main thread */
1108 [[[NSApplication sharedApplication] dockTile] performSelectorOnMainThread:@selector(display) withObject:nil waitUntilDone:NO];
1109
1110 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1111 GL_RESTORE_STATE;
1112 }
1113 }
1114
1115 /* Clear background to transparent */
1116 glClear(GL_COLOR_BUFFER_BIT);
1117
1118 /* Blit the content of the FBO to the screen. todo: check for
1119 * optimization with display lists. */
1120 GLint i;
1121 for (i = 0; i < m_cClipRects; ++i)
1122 {
1123 GLint x1 = m_paClipRects[4*i];
1124 GLint y1 = r.size.height - m_paClipRects[4*i+1];
1125 GLint x2 = m_paClipRects[4*i+2];
1126 GLint y2 = r.size.height - m_paClipRects[4*i+3];
1127 glBegin(GL_QUADS);
1128 {
1129 glTexCoord2i(x1, y1); glVertex2i(x1, y1);
1130 glTexCoord2i(x1, y2); glVertex2i(x1, y2);
1131 glTexCoord2i(x2, y2); glVertex2i(x2, y2);
1132 glTexCoord2i(x2, y1); glVertex2i(x2, y1);
1133 }
1134 glEnd();
1135 }
1136 [m_pSharedGLCtx flushBuffer];
1137 [m_pGLCtx makeCurrentContext];
1138 }
1139 }
1140}
1141
1142- (void)clearVisibleRegions
1143{
1144 if(m_paClipRects)
1145 {
1146 RTMemFree(m_paClipRects);
1147 m_paClipRects = NULL;
1148 }
1149 m_cClipRects = 0;
1150}
1151
1152- (void)setVisibleRegions:(GLint)cRects paRects:(GLint*)paRects
1153{
1154 DEBUG_MSG_1(("New region recieved\n"));
1155
1156 [self clearVisibleRegions];
1157
1158 if (cRects>0)
1159 {
1160 m_paClipRects = (GLint*)RTMemAlloc(sizeof(GLint) * 4 * cRects);
1161 m_cClipRects = cRects;
1162 memcpy(m_paClipRects, paRects, sizeof(GLint) * 4 * cRects);
1163 }
1164}
1165
1166- (NSView*)dockTileScreen
1167{
1168 NSView *contentView = [[[NSApplication sharedApplication] dockTile] contentView];
1169 NSView *screenContent = nil;
1170 if ([contentView respondsToSelector:@selector(screenContent)])
1171 screenContent = [contentView performSelector:@selector(screenContent)];
1172 return screenContent;
1173}
1174
1175- (void)reshapeDockTile
1176{
1177 NSRect dockFrame = [[self dockTileScreen] frame];
1178 NSRect parentFrame = [m_pParentView frame];
1179
1180 m_FBOThumbScaleX = (float)dockFrame.size.width / parentFrame.size.width;
1181 m_FBOThumbScaleY = (float)dockFrame.size.height / parentFrame.size.height;
1182 NSRect newFrame = NSMakeRect ((int)(m_Pos.x * m_FBOThumbScaleX), (int)(dockFrame.size.height - (m_Pos.y + m_Size.height - m_RootShift.y) * m_FBOThumbScaleY), (int)(m_Size.width * m_FBOThumbScaleX), (int)(m_Size.height * m_FBOThumbScaleY));
1183// NSRect newFrame = NSMakeRect ((int)roundf(m_Pos.x * m_FBOThumbScaleX), (int)roundf(dockFrame.size.height - (m_Pos.y + m_Size.height) * m_FBOThumbScaleY), (int)roundf(m_Size.width * m_FBOThumbScaleX), (int)roundf(m_Size.height * m_FBOThumbScaleY));
1184// NSRect newFrame = NSMakeRect ((m_Pos.x * m_FBOThumbScaleX), (dockFrame.size.height - (m_Pos.y + m_Size.height) * m_FBOThumbScaleY), (m_Size.width * m_FBOThumbScaleX), (m_Size.height * m_FBOThumbScaleY));
1185// printf ("%f %f %f %f - %f %f\n", newFrame.origin.x, newFrame.origin.y, newFrame.size.width, newFrame.size.height, m_Size.height, m_FBOThumbScaleY);
1186 [m_DockTileView setFrame: newFrame];
1187}
1188
1189@end
1190
1191/********************************************************************************
1192*
1193* OpenGL context management
1194*
1195********************************************************************************/
1196void cocoaGLCtxCreate(NativeGLCtxRef *ppCtx, GLbitfield fVisParams)
1197{
1198 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1199
1200 NSOpenGLPixelFormatAttribute attribs[24] =
1201 {
1202 NSOpenGLPFAWindow,
1203 NSOpenGLPFAAccelerated,
1204 NSOpenGLPFAColorSize, (NSOpenGLPixelFormatAttribute)24
1205 };
1206
1207 int i = 4;
1208 if (fVisParams & CR_ALPHA_BIT)
1209 {
1210 DEBUG_MSG(("CR_ALPHA_BIT requested\n"));
1211 attribs[i++] = NSOpenGLPFAAlphaSize;
1212 attribs[i++] = 8;
1213 }
1214 if (fVisParams & CR_DEPTH_BIT)
1215 {
1216 DEBUG_MSG(("CR_DEPTH_BIT requested\n"));
1217 attribs[i++] = NSOpenGLPFADepthSize;
1218 attribs[i++] = 24;
1219 }
1220 if (fVisParams & CR_STENCIL_BIT)
1221 {
1222 DEBUG_MSG(("CR_STENCIL_BIT requested\n"));
1223 attribs[i++] = NSOpenGLPFAStencilSize;
1224 attribs[i++] = 8;
1225 }
1226 if (fVisParams & CR_ACCUM_BIT)
1227 {
1228 DEBUG_MSG(("CR_ACCUM_BIT requested\n"));
1229 attribs[i++] = NSOpenGLPFAAccumSize;
1230 if (fVisParams & CR_ALPHA_BIT)
1231 attribs[i++] = 32;
1232 else
1233 attribs[i++] = 24;
1234 }
1235 if (fVisParams & CR_MULTISAMPLE_BIT)
1236 {
1237 DEBUG_MSG(("CR_MULTISAMPLE_BIT requested\n"));
1238 attribs[i++] = NSOpenGLPFASampleBuffers;
1239 attribs[i++] = 1;
1240 attribs[i++] = NSOpenGLPFASamples;
1241 attribs[i++] = 4;
1242 }
1243 if (fVisParams & CR_DOUBLE_BIT)
1244 {
1245 DEBUG_MSG(("CR_DOUBLE_BIT requested\n"));
1246 attribs[i++] = NSOpenGLPFADoubleBuffer;
1247 }
1248 if (fVisParams & CR_STEREO_BIT)
1249 {
1250 DEBUG_MSG(("CR_DOUBLE_BIT requested\n"));
1251 attribs[i++] = NSOpenGLPFAStereo;
1252 }
1253
1254 /* Mark the end */
1255 attribs[i++] = 0;
1256
1257 /* Choose a pixel format */
1258 NSOpenGLPixelFormat* pFmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
1259
1260 if (pFmt)
1261 {
1262 *ppCtx = [[OverlayOpenGLContext alloc] initWithFormat:pFmt shareContext:nil];
1263
1264 /* Enable multi threaded OpenGL engine */
1265// CGLContextObj cglCtx = [*ppCtx CGLContextObj];
1266// CGLError err = CGLEnable(cglCtx, kCGLCEMPEngine);
1267// if (err != kCGLNoError)
1268// printf ("Couldn't enable MT OpenGL engine!\n");
1269
1270 DEBUG_MSG(("New context %X\n", (uint)*ppCtx));
1271 }
1272
1273 [pPool release];
1274}
1275
1276void cocoaGLCtxDestroy(NativeGLCtxRef pCtx)
1277{
1278 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1279
1280// [pCtx release];
1281
1282 [pPool release];
1283}
1284
1285/********************************************************************************
1286*
1287* View management
1288*
1289********************************************************************************/
1290void cocoaViewCreate(NativeViewRef *ppView, NativeViewRef pParentView, GLbitfield fVisParams)
1291{
1292 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1293
1294 /* Create our worker view */
1295 OverlayView* pView = [[OverlayView alloc] initWithFrame:NSZeroRect thread:RTThreadSelf() parentView:pParentView];
1296
1297 if (pView)
1298 {
1299 /* We need a real window as container for the view */
1300 [[OverlayWindow alloc] initWithParentView:pParentView overlayView:pView];
1301 /* Return the freshly created overlay view */
1302 *ppView = pView;
1303 }
1304
1305 [pPool release];
1306}
1307
1308void cocoaViewDestroy(NativeViewRef pView)
1309{
1310 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1311
1312 /* Hide the view early */
1313 [pView setHidden: YES];
1314
1315 NSWindow *win = [pView window];
1316 [[NSNotificationCenter defaultCenter] removeObserver:win];
1317 [win setContentView: nil];
1318 [[win parentWindow] removeChildWindow: win];
1319 int b = [win retainCount];
1320// for (; b > 1; --b)
1321// [win performSelector:@selector(release)]
1322 [win performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO];
1323// [win release];
1324
1325 /* There seems to be a bug in the performSelector method which is called in
1326 * parentWindowChanged above. The object is retained but not released. This
1327 * results in an unbalanced reference count, which is here manually
1328 * decremented. */
1329 int a = [pView retainCount];
1330// for (; a > 1; --a)
1331 [pView performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO];
1332// [pView release];
1333
1334 [pPool release];
1335}
1336
1337void cocoaViewShow(NativeViewRef pView, GLboolean fShowIt)
1338{
1339 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1340
1341 [pView setHidden: fShowIt==GL_TRUE?NO:YES];
1342
1343 [pPool release];
1344}
1345
1346void cocoaViewDisplay(NativeViewRef pView)
1347{
1348 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1349
1350 [(OverlayView*)pView swapFBO];
1351
1352 [pPool release];
1353
1354}
1355
1356void cocoaViewSetPosition(NativeViewRef pView, NativeViewRef pParentView, int x, int y)
1357{
1358 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1359
1360 [(OverlayView*)pView setPos:NSMakePoint(x, y)];
1361
1362 [pPool release];
1363}
1364
1365void cocoaViewSetSize(NativeViewRef pView, int w, int h)
1366{
1367 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1368
1369 [(OverlayView*)pView setSize:NSMakeSize(w, h)];
1370
1371 [pPool release];
1372}
1373
1374void cocoaViewGetGeometry(NativeViewRef pView, int *pX, int *pY, int *pW, int *pH)
1375{
1376 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1377
1378 NSRect frame = [[pView window] frame];
1379 *pX = frame.origin.x;
1380 *pY = frame.origin.y;
1381 *pW = frame.size.width;
1382 *pH = frame.size.height;
1383
1384 [pPool release];
1385}
1386
1387void cocoaViewMakeCurrentContext(NativeViewRef pView, NativeGLCtxRef pCtx)
1388{
1389 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1390
1391 [(OverlayView*)pView setGLCtx:pCtx];
1392 [(OverlayView*)pView makeCurrentFBO];
1393
1394 [pPool release];
1395}
1396
1397void cocoaViewSetVisibleRegion(NativeViewRef pView, GLint cRects, GLint* paRects)
1398{
1399 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1400
1401 [(OverlayView*)pView setVisibleRegions:cRects paRects:paRects];
1402
1403 [pPool release];
1404}
1405
1406/********************************************************************************
1407*
1408* Additional OpenGL wrapper
1409*
1410********************************************************************************/
1411void cocoaFlush()
1412{
1413 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1414
1415// glFlush();
1416// return;
1417
1418 DEBUG_MSG_1(("glFlush called\n"));
1419
1420#ifdef FBO
1421# if 0
1422 NSOpenGLContext *pCtx = [NSOpenGLContext currentContext];
1423 if (pCtx)
1424 {
1425 NSView *pView = [pCtx view];
1426 if (pView)
1427 {
1428 if ([pView respondsToSelector:@selector(flushFBO)])
1429 [pView performSelector:@selector(flushFBO)];
1430 }
1431 }
1432# endif
1433#else
1434 glFlush();
1435#endif
1436
1437 [pPool release];
1438}
1439
1440void cocoaFinish()
1441{
1442 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1443
1444 DEBUG_MSG_1(("glFinish called\n"));
1445
1446#ifdef FBO
1447 NSOpenGLContext *pCtx = [NSOpenGLContext currentContext];
1448 if (pCtx)
1449 {
1450 NSView *pView = [pCtx view];
1451 if (pView)
1452 {
1453 if ([pView respondsToSelector:@selector(finishFBO)])
1454 [pView performSelector:@selector(finishFBO)];
1455 }
1456 }
1457#else
1458 glFinish();
1459#endif
1460
1461 [pPool release];
1462}
1463
1464void cocoaBindFramebufferEXT(GLenum target, GLuint framebuffer)
1465{
1466 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1467
1468 DEBUG_MSG_1(("glRenderspuBindFramebufferEXT called %d\n", framebuffer));
1469
1470#ifdef FBO
1471 if (framebuffer != 0)
1472 glBindFramebufferEXT(target, framebuffer);
1473 else
1474 {
1475 NSOpenGLContext *pCtx = [NSOpenGLContext currentContext];
1476 if (pCtx)
1477 {
1478 NSView *pView = [pCtx view];
1479 if (pView)
1480 {
1481 if ([pView respondsToSelector:@selector(bindFBO)])
1482 [pView performSelector:@selector(bindFBO)];
1483 }
1484 }
1485 }
1486#else
1487 glBindFramebufferEXT(target, framebuffer);
1488#endif
1489
1490 [pPool release];
1491}
1492
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette