VirtualBox

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

Last change on this file since 34079 was 33595, checked in by vboxsync, 14 years ago

src/*: more spelling fixes (logging), thanks Timeless!

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