VirtualBox

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

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

crOpenGL: correctly rebing view fbo after snapshot load

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

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