VirtualBox

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

Last change on this file since 39436 was 39206, checked in by vboxsync, 13 years ago

Made OpenGL build against the Mac OS X 10.7 SDK. Some cleanups.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 60.2 KB
Line 
1/* $Id: renderspu_cocoa_helper.m 39206 2011-11-04 15:16:16Z vboxsync $ */
2/** @file
3 * VirtualBox OpenGL Cocoa Window System Helper Implementation.
4 */
5
6/*
7 * Copyright (C) 2009-2011 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/** @page pg_opengl_cocoa OpenGL - Cocoa Window System Helper
30 *
31 * How this works:
32 * In general it is not so easy like on the other platforms, cause Cocoa
33 * doesn't support any clipping of already painted stuff. In Mac OS X there is
34 * the concept of translucent canvas's e.g. windows and there it is just
35 * painted what should be visible to the user. Unfortunately this isn't the
36 * concept of chromium. Therefor I reroute all OpenGL operation from the guest
37 * to a frame buffer object (FBO). This is a OpenGL extension, which is
38 * supported by all OS X versions we support (AFAIC tell). Of course the guest
39 * doesn't know that and we have to make sure that the OpenGL state always is
40 * in the right state to paint into the FBO and not to the front/back buffer.
41 * Several functions below (like cocoaBindFramebufferEXT, cocoaGetIntegerv,
42 * ...) doing this. When a swap or finish is triggered by the guest, the
43 * content (which is already bound to an texture) is painted on the screen
44 * within a separate OpenGL context. This allows the usage of the same
45 * resources (texture ids, buffers ...) but at the same time having an
46 * different internal OpenGL state. Another advantage is that we can paint a
47 * thumbnail of the current output in a much more smaller (GPU accelerated
48 * scale) version on a third context and use glReadPixels to get the actual
49 * data. glReadPixels is a very slow operation, but as we just use a much more
50 * smaller image, we can handle it (anyway this is only done 5 times per
51 * second).
52 *
53 * Other things to know:
54 * - If the guest request double buffering, we have to make sure there are two
55 * buffers. We use the same FBO with 2 color attachments. Also glDrawBuffer
56 * and glReadBuffer is intercepted to make sure it is painted/read to/from
57 * the correct buffers. On swap our buffers are swapped and not the
58 * front/back buffer.
59 * - If the guest request a depth/stencil buffer, a combined render buffer for
60 * this is created.
61 * - If the size of the guest OpenGL window changes, all FBO's, textures, ...
62 * need to be recreated.
63 * - We need to track any changes to the parent window
64 * (create/destroy/move/resize). The various classes like OverlayHelperView,
65 * OverlayWindow, ... are there for.
66 * - The HGCM service runs on a other thread than the Main GUI. Keeps this
67 * always in mind (see e.g. performSelectorOnMainThread in renderFBOToView)
68 * - We make heavy use of late binding. We can not be sure that the GUI (or any
69 * other third party GUI), overwrite our NSOpenGLContext. So we always ask if
70 * this is our own one, before use. Really neat concept of Objective-C/Cocoa
71 * ;)
72 */
73
74/* Debug macros */
75#define FBO 1 /* Disable this to see how the output is without the FBO in the middle of the processing chain. */
76#if 0
77# define SHOW_WINDOW_BACKGROUND 1 /* Define this to see the window background even if the window is clipped */
78# define DEBUG_VERBOSE /* Define this to get some debug info about the messages flow. */
79#endif
80
81#ifdef DEBUG_poetzsch
82# define DEBUG_MSG(text) \
83 printf text
84#else
85# define DEBUG_MSG(text) \
86 do {} while (0)
87#endif
88
89#ifdef DEBUG_VERBOSE
90# define DEBUG_MSG_1(text) \
91 DEBUG_MSG(text)
92#else
93# define DEBUG_MSG_1(text) \
94 do {} while (0)
95#endif
96
97#ifdef DEBUG_poetzsch
98# define CHECK_GL_ERROR()\
99 do \
100 { \
101 checkGLError(__FILE__, __LINE__); \
102 }while (0);
103
104 static void checkGLError(char *file, int line)
105 {
106 GLenum g = glGetError();
107 if (g != GL_NO_ERROR)
108 {
109 char *errStr;
110 switch (g)
111 {
112 case GL_INVALID_ENUM: errStr = RTStrDup("GL_INVALID_ENUM"); break;
113 case GL_INVALID_VALUE: errStr = RTStrDup("GL_INVALID_VALUE"); break;
114 case GL_INVALID_OPERATION: errStr = RTStrDup("GL_INVALID_OPERATION"); break;
115 case GL_STACK_OVERFLOW: errStr = RTStrDup("GL_STACK_OVERFLOW"); break;
116 case GL_STACK_UNDERFLOW: errStr = RTStrDup("GL_STACK_UNDERFLOW"); break;
117 case GL_OUT_OF_MEMORY: errStr = RTStrDup("GL_OUT_OF_MEMORY"); break;
118 case GL_TABLE_TOO_LARGE: errStr = RTStrDup("GL_TABLE_TOO_LARGE"); break;
119 default: errStr = RTStrDup("UNKNOWN"); break;
120 }
121 DEBUG_MSG(("%s:%d: glError %d (%s)\n", file, line, g, errStr));
122 RTMemFree(errStr);
123 }
124 }
125#else
126# define CHECK_GL_ERROR()\
127 do {} while (0)
128#endif
129
130#define GL_SAVE_STATE \
131 do \
132 { \
133 glPushAttrib(GL_ALL_ATTRIB_BITS); \
134 glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS); \
135 glMatrixMode(GL_PROJECTION); \
136 glPushMatrix(); \
137 glMatrixMode(GL_TEXTURE); \
138 glPushMatrix(); \
139 glMatrixMode(GL_COLOR); \
140 glPushMatrix(); \
141 glMatrixMode(GL_MODELVIEW); \
142 glPushMatrix(); \
143 } \
144 while(0);
145
146#define GL_RESTORE_STATE \
147 do \
148 { \
149 glMatrixMode(GL_MODELVIEW); \
150 glPopMatrix(); \
151 glMatrixMode(GL_COLOR); \
152 glPopMatrix(); \
153 glMatrixMode(GL_TEXTURE); \
154 glPopMatrix(); \
155 glMatrixMode(GL_PROJECTION); \
156 glPopMatrix(); \
157 glPopClientAttrib(); \
158 glPopAttrib(); \
159 } \
160 while(0);
161
162/** Custom OpenGL context class.
163 *
164 * This implementation doesn't allow to set a view to the
165 * context, but save the view for later use. Also it saves a copy of the
166 * pixel format used to create that context for later use. */
167@interface OverlayOpenGLContext: NSOpenGLContext
168{
169@private
170 NSOpenGLPixelFormat *m_pPixelFormat;
171 NSView *m_pView;
172}
173- (NSOpenGLPixelFormat*)openGLPixelFormat;
174@end
175
176@class DockOverlayView;
177
178/** The custom view class.
179 * This is the main class of the cocoa OpenGL implementation. It
180 * manages an frame buffer object for the rendering of the guest
181 * applications. The guest applications render in this frame buffer which
182 * is bind to an OpenGL texture. To display the guest content, an secondary
183 * shared OpenGL context of the main OpenGL context is created. The secondary
184 * context is marked as non opaque & the texture is displayed on an object
185 * which is composed out of the several visible region rectangles. */
186@interface OverlayView: NSView
187{
188@private
189 NSView *m_pParentView;
190 NSWindow *m_pOverlayWin;
191
192 NSOpenGLContext *m_pGLCtx;
193 NSOpenGLContext *m_pSharedGLCtx;
194 RTTHREAD mThread;
195
196#ifdef FBO
197 GLuint m_FBOId;
198 /* FBO handling */
199 GLuint m_FBOTexBackId;
200 GLuint m_FBOTexFrontId;
201 GLuint m_FBOAttBackId;
202 GLuint m_FBOAttFrontId;
203 GLuint m_FBODepthStencilPackedId;
204 NSSize m_FBOTexSize;
205
206 bool m_fFrontDrawing;
207#endif
208
209 /** The corresponding dock tile view of this OpenGL view & all helper
210 * members. */
211 DockOverlayView *m_DockTileView;
212
213 GLuint m_FBOThumbId;
214 GLuint m_FBOThumbTexId;
215 GLfloat m_FBOThumbScaleX;
216 GLfloat m_FBOThumbScaleY;
217 uint64_t m_uiDockUpdateTime;
218
219 /* For clipping */
220 GLint m_cClipRects;
221 GLint *m_paClipRects;
222
223 /* Position/Size tracking */
224 NSPoint m_Pos;
225 NSSize m_Size;
226
227 /** This is necessary for clipping on the root window */
228 NSPoint m_RootShift;
229}
230- (id)initWithFrame:(NSRect)frame thread:(RTTHREAD)aThread parentView:(NSView*)pParentView;
231- (void)setGLCtx:(NSOpenGLContext*)pCtx;
232- (NSOpenGLContext*)glCtx;
233
234- (void)setParentView: (NSView*)view;
235- (NSView*)parentView;
236- (void)setOverlayWin: (NSWindow*)win;
237- (NSWindow*)overlayWin;
238
239- (void)setPos:(NSPoint)pos;
240- (NSPoint)pos;
241- (void)setSize:(NSSize)size;
242- (NSSize)size;
243- (void)updateViewport;
244- (void)reshape;
245
246- (void)createFBO;
247- (void)deleteFBO;
248
249- (bool)isCurrentFBO;
250- (void)updateFBO;
251- (void)makeCurrentFBO;
252- (void)swapFBO;
253- (void)flushFBO;
254- (void)stateInfo:(GLenum)pname withParams:(GLint*)params;
255- (void)finishFBO;
256- (void)bindFBO:(GLenum)target withFrameBuffer:(GLuint)framebuffer;
257- (void)tryDraw;
258- (void)renderFBOToView;
259- (void)renderFBOToDockTile;
260
261- (void)clearVisibleRegions;
262- (void)setVisibleRegions:(GLint)cRects paRects:(GLint*)paRects;
263
264- (NSView*)dockTileScreen;
265- (void)reshapeDockTile;
266@end
267
268/** Helper view.
269 *
270 * This view is added as a sub view of the parent view to track
271 * main window changes. Whenever the main window is changed
272 * (which happens on fullscreen/seamless entry/exit) the overlay
273 * window is informed & can add them self as a child window
274 * again. */
275@class OverlayWindow;
276@interface OverlayHelperView: NSView
277{
278@private
279 OverlayWindow *m_pOverlayWindow;
280}
281-(id)initWithOverlayWindow:(OverlayWindow*)pOverlayWindow;
282@end
283
284/** Custom window class.
285 *
286 * This is the overlay window which contains our custom NSView.
287 * Its a direct child of the Qt Main window. It marks its background
288 * transparent & non opaque to make clipping possible. It also disable mouse
289 * events and handle frame change events of the parent view. */
290@interface OverlayWindow: NSWindow
291{
292@private
293 NSView *m_pParentView;
294 OverlayView *m_pOverlayView;
295 OverlayHelperView *m_pOverlayHelperView;
296 NSThread *m_Thread;
297}
298- (id)initWithParentView:(NSView*)pParentView overlayView:(OverlayView*)pOverlayView;
299- (void)parentWindowFrameChanged:(NSNotification *)note;
300- (void)parentWindowChanged:(NSWindow*)pWindow;
301@end
302
303@interface DockOverlayView: NSView
304{
305 NSBitmapImageRep *m_ThumbBitmap;
306 NSImage *m_ThumbImage;
307 NSLock *m_Lock;
308}
309- (void)dealloc;
310- (void)cleanup;
311- (void)lock;
312- (void)unlock;
313- (void)setFrame:(NSRect)frame;
314- (void)drawRect:(NSRect)aRect;
315- (NSBitmapImageRep*)thumbBitmap;
316- (NSImage*)thumbImage;
317@end
318
319@implementation DockOverlayView
320- (id)init
321{
322 self = [super init];
323
324 if (self)
325 {
326 /* We need a lock cause the thumb image could be accessed from the main
327 * thread when someone is calling display on the dock tile & from the
328 * OpenGL thread when the thumbnail is updated. */
329 m_Lock = [[NSLock alloc] init];
330 }
331
332 return self;
333}
334
335- (void)dealloc
336{
337 [self cleanup];
338 [m_Lock release];
339
340 [super dealloc];
341}
342
343- (void)cleanup
344{
345 if (m_ThumbImage != nil)
346 {
347 [m_ThumbImage release];
348 m_ThumbImage = nil;
349 }
350 if (m_ThumbBitmap != nil)
351 {
352 [m_ThumbBitmap release];
353 m_ThumbBitmap = nil;
354 }
355}
356
357- (void)lock
358{
359 [m_Lock lock];
360}
361
362- (void)unlock
363{
364 [m_Lock unlock];
365}
366
367- (void)setFrame:(NSRect)frame
368{
369 [super setFrame:frame];
370
371 [self lock];
372 [self cleanup];
373
374 if ( frame.size.width > 0
375 && frame.size.height > 0)
376 {
377 /* Create a buffer for our thumbnail image. Its in the size of this view. */
378 m_ThumbBitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
379 pixelsWide:frame.size.width
380 pixelsHigh:frame.size.height
381 bitsPerSample:8
382 samplesPerPixel:4
383 hasAlpha:YES
384 isPlanar:NO
385 colorSpaceName:NSDeviceRGBColorSpace
386 bitmapFormat:NSAlphaFirstBitmapFormat
387 bytesPerRow:frame.size.width * 4
388 bitsPerPixel:8 * 4];
389 m_ThumbImage = [[NSImage alloc] initWithSize:[m_ThumbBitmap size]];
390 [m_ThumbImage addRepresentation:m_ThumbBitmap];
391 }
392 [self unlock];
393}
394
395- (BOOL)isFlipped
396{
397 return YES;
398}
399
400- (void)drawRect:(NSRect)aRect
401{
402 NSRect frame;
403
404 [self lock];
405#ifdef SHOW_WINDOW_BACKGROUND
406 [[NSColor colorWithCalibratedRed:1.0 green:0.0 blue:0.0 alpha:0.7] set];
407 frame = [self frame];
408 [NSBezierPath fillRect:NSMakeRect(0, 0, frame.size.width, frame.size.height)];
409#endif /* SHOW_WINDOW_BACKGROUND */
410 if (m_ThumbImage != nil)
411 [m_ThumbImage drawAtPoint:NSMakePoint(0, 0) fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
412 [self unlock];
413}
414
415- (NSBitmapImageRep*)thumbBitmap
416{
417 return m_ThumbBitmap;
418}
419
420- (NSImage*)thumbImage
421{
422 return m_ThumbImage;
423}
424@end
425
426/********************************************************************************
427*
428* OverlayOpenGLContext class implementation
429*
430********************************************************************************/
431@implementation OverlayOpenGLContext
432
433-(id)initWithFormat:(NSOpenGLPixelFormat*)format shareContext:(NSOpenGLContext*)share
434{
435 m_pPixelFormat = NULL;
436 m_pView = NULL;
437
438 self = [super initWithFormat:format shareContext:share];
439 if (self)
440 m_pPixelFormat = format;
441
442 DEBUG_MSG(("OCTX(%p): init OverlayOpenGLContext\n", (void*)self));
443
444 return self;
445}
446
447- (void)dealloc
448{
449 DEBUG_MSG(("OCTX(%p): dealloc OverlayOpenGLContext\n", (void*)self));
450
451 [m_pPixelFormat release];
452
453 [super dealloc];
454}
455
456-(bool)isDoubleBuffer
457{
458 GLint val;
459 [m_pPixelFormat getValues:&val forAttribute:NSOpenGLPFADoubleBuffer forVirtualScreen:0];
460 return val == GL_TRUE ? YES : NO;
461}
462
463-(void)setView:(NSView*)view
464{
465 DEBUG_MSG(("OCTX(%p): setView: new view: %p\n", (void*)self, (void*)view));
466
467#ifdef FBO
468 m_pView = view;;
469#else
470 [super setView: view];
471#endif
472}
473
474-(NSView*)view
475{
476#ifdef FBO
477 return m_pView;
478#else
479 return [super view];
480#endif
481}
482
483-(void)clearDrawable
484{
485 DEBUG_MSG(("OCTX(%p): clearDrawable\n", (void*)self));
486
487 m_pView = NULL;;
488 [super clearDrawable];
489}
490
491-(NSOpenGLPixelFormat*)openGLPixelFormat
492{
493 return m_pPixelFormat;
494}
495
496@end
497
498/********************************************************************************
499*
500* OverlayHelperView class implementation
501*
502********************************************************************************/
503@implementation OverlayHelperView
504
505-(id)initWithOverlayWindow:(OverlayWindow*)pOverlayWindow
506{
507 self = [super initWithFrame:NSZeroRect];
508
509 m_pOverlayWindow = pOverlayWindow;
510
511 DEBUG_MSG(("OHVW(%p): init OverlayHelperView\n", (void*)self));
512
513 return self;
514}
515
516-(void)viewDidMoveToWindow
517{
518 DEBUG_MSG(("OHVW(%p): viewDidMoveToWindow: new win: %p\n", (void*)self, (void*)[self window]));
519
520 [m_pOverlayWindow parentWindowChanged:[self window]];
521}
522
523@end
524
525/********************************************************************************
526*
527* OverlayWindow class implementation
528*
529********************************************************************************/
530@implementation OverlayWindow
531
532- (id)initWithParentView:(NSView*)pParentView overlayView:(OverlayView*)pOverlayView
533{
534 NSWindow *pParentWin = nil;
535
536 if((self = [super initWithContentRect:NSZeroRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]))
537 {
538 m_pParentView = pParentView;
539 m_pOverlayView = pOverlayView;
540 m_Thread = [NSThread currentThread];
541
542 [m_pOverlayView setOverlayWin: self];
543
544 m_pOverlayHelperView = [[OverlayHelperView alloc] initWithOverlayWindow:self];
545 /* Add the helper view as a child of the parent view to get notifications */
546 [pParentView addSubview:m_pOverlayHelperView];
547
548 /* Make sure this window is transparent */
549#ifdef SHOW_WINDOW_BACKGROUND
550 /* For debugging */
551 [self setBackgroundColor:[NSColor colorWithCalibratedRed:1.0 green:0.0 blue:0.0 alpha:0.7]];
552#else
553 [self setBackgroundColor:[NSColor clearColor]];
554#endif
555 [self setOpaque:NO];
556 [self setAlphaValue:.999];
557 /* Disable mouse events for this window */
558 [self setIgnoresMouseEvents:YES];
559
560 pParentWin = [m_pParentView window];
561
562 /* Initial set the position to the parents view top/left (Compiz fix). */
563 [self setFrameOrigin:
564 [pParentWin convertBaseToScreen:
565 [m_pParentView convertPoint:NSZeroPoint toView:nil]]];
566
567 /* Set the overlay view as our content view */
568 [self setContentView:m_pOverlayView];
569
570 /* Add ourself as a child to the parent views window. Note: this has to
571 * be done last so that everything else is setup in
572 * parentWindowChanged. */
573 [pParentWin addChildWindow:self ordered:NSWindowAbove];
574 }
575 DEBUG_MSG(("OWIN(%p): init OverlayWindow\n", (void*)self));
576
577 return self;
578}
579
580- (void)dealloc
581{
582 DEBUG_MSG(("OWIN(%p): dealloc OverlayWindow\n", (void*)self));
583
584 [[NSNotificationCenter defaultCenter] removeObserver:self];
585
586 [m_pOverlayHelperView removeFromSuperview];
587 [m_pOverlayHelperView release];
588
589 [super dealloc];
590}
591
592- (void)parentWindowFrameChanged:(NSNotification*)pNote
593{
594 DEBUG_MSG(("OWIN(%p): parentWindowFrameChanged\n", (void*)self));
595
596 /* Reposition this window with the help of the OverlayView. Perform the
597 * call in the OpenGL thread. */
598 /*
599 [m_pOverlayView performSelector:@selector(reshape) onThread:m_Thread withObject:nil waitUntilDone:YES];
600 */
601
602 [m_pOverlayView reshape];
603}
604
605- (void)parentWindowChanged:(NSWindow*)pWindow
606{
607 DEBUG_MSG(("OWIN(%p): parentWindowChanged\n", (void*)self));
608
609 [[NSNotificationCenter defaultCenter] removeObserver:self];
610
611 if(pWindow != nil)
612 {
613 /* Ask to get notifications when our parent window frame changes. */
614 [[NSNotificationCenter defaultCenter]
615 addObserver:self
616 selector:@selector(parentWindowFrameChanged:)
617 name:NSWindowDidResizeNotification
618 object:pWindow];
619 /* Add us self as child window */
620 [pWindow addChildWindow:self ordered:NSWindowAbove];
621 /* Reshape the overlay view after a short waiting time to let the main
622 * window resize itself properly. */
623 /*
624 [m_pOverlayView performSelector:@selector(reshape) withObject:nil afterDelay:0.2];
625 [NSTimer scheduledTimerWithTimeInterval:0.2 target:m_pOverlayView selector:@selector(reshape) userInfo:nil repeats:NO];
626 */
627 [m_pOverlayView reshape];
628 }
629}
630
631@end
632
633/********************************************************************************
634*
635* OverlayView class implementation
636*
637********************************************************************************/
638@implementation OverlayView
639
640- (id)initWithFrame:(NSRect)frame thread:(RTTHREAD)aThread parentView:(NSView*)pParentView
641{
642 m_pParentView = pParentView;
643 /* Make some reasonable defaults */
644 m_pGLCtx = nil;
645 m_pSharedGLCtx = nil;
646 mThread = aThread;
647#ifdef FBO
648 m_FBOId = 0;
649 m_FBOTexBackId = 0;
650 m_FBOTexFrontId = 0;
651 m_FBOAttBackId = GL_COLOR_ATTACHMENT0_EXT;
652 m_FBOAttFrontId = GL_COLOR_ATTACHMENT1_EXT;
653 m_FBODepthStencilPackedId = 0;
654 m_FBOTexSize = NSZeroSize;
655#endif
656 m_FBOThumbId = 0;
657 m_FBOThumbTexId = 0;
658 m_cClipRects = 0;
659 m_paClipRects = NULL;
660 m_Pos = NSZeroPoint;
661 m_Size = NSMakeSize(1, 1);
662 m_RootShift = NSZeroPoint;
663
664 self = [super initWithFrame:frame];
665
666 DEBUG_MSG(("OVIW(%p): init OverlayView\n", (void*)self));
667
668 return self;
669}
670
671- (void)dealloc
672{
673 DEBUG_MSG(("OVIW(%p): dealloc OverlayView\n", (void*)self));
674
675 [self deleteFBO];
676
677 if (m_pGLCtx)
678 {
679 if ([m_pGLCtx view] == self)
680 [m_pGLCtx clearDrawable];
681 }
682 if (m_pSharedGLCtx)
683 {
684 if ([m_pSharedGLCtx view] == self)
685 [m_pSharedGLCtx clearDrawable];
686
687 [m_pSharedGLCtx release];
688 }
689
690 [self clearVisibleRegions];
691
692 [super dealloc];
693}
694
695- (void)drawRect:(NSRect)aRect
696{
697 /* Do nothing */
698}
699
700- (void)setGLCtx:(NSOpenGLContext*)pCtx
701{
702 DEBUG_MSG(("OVIW(%p): setGLCtx: new ctx: %p\n", (void*)self, (void*)pCtx));
703
704 m_pGLCtx = pCtx;
705}
706
707- (NSOpenGLContext*)glCtx
708{
709 return m_pGLCtx;
710}
711
712- (NSView*)parentView
713{
714 return m_pParentView;
715}
716
717- (void)setParentView:(NSView*)pView
718{
719 DEBUG_MSG(("OVIW(%p): setParentView: new view: %p\n", (void*)self, (void*)pView));
720
721 m_pParentView = pView;
722}
723
724- (void)setOverlayWin:(NSWindow*)pWin
725{
726 DEBUG_MSG(("OVIW(%p): setOverlayWin: new win: %p\n", (void*)self, (void*)pWin));
727
728 m_pOverlayWin = pWin;
729}
730
731- (NSWindow*)overlayWin
732{
733 return m_pOverlayWin;
734}
735
736- (void)setPos:(NSPoint)pos
737{
738 DEBUG_MSG(("OVIW(%p): setPos: new pos: %d, %d\n", (void*)self, (int)pos.x, (int)pos.y));
739
740 m_Pos = pos;
741
742 [self reshape];
743}
744
745- (NSPoint)pos
746{
747 return m_Pos;
748}
749
750- (void)setSize:(NSSize)size
751{
752 m_Size = size;
753
754#ifdef FBO
755 if (m_FBOId)
756 {
757 DEBUG_MSG(("OVIW(%p): setSize: new size: %dx%d\n", (void*)self, (int)size.width, (int)size.height));
758 [self reshape];
759 [self updateFBO];
760 /* have to rebind GL_TEXTURE_RECTANGLE_ARB as m_FBOTexId could be changed in updateFBO call */
761 [self updateViewport];
762 }
763 else
764#endif
765 {
766 DEBUG_MSG(("OVIW(%p): setSize (no FBO): new size: %dx%d\n", (void*)self, (int)size.width, (int)size.height));
767 [self reshape];
768 [self updateFBO];
769 }
770}
771
772- (NSSize)size
773{
774 return m_Size;
775}
776
777- (void)updateViewport
778{
779 NSRect r;
780
781 DEBUG_MSG(("OVIW(%p): updateViewport\n", (void*)self));
782
783#ifdef FBO
784 if (m_pSharedGLCtx)
785 {
786 /* Update the viewport for our OpenGL view */
787 DEBUG_MSG(("OVIW(%p): makeCurrent (shared) %p\n", (void*)self, (void*)m_pSharedGLCtx));
788 [m_pSharedGLCtx makeCurrentContext];
789 [m_pSharedGLCtx update];
790
791 r = [self frame];
792 /* Setup all matrices */
793 glMatrixMode(GL_PROJECTION);
794 glLoadIdentity();
795 glViewport(0, 0, r.size.width, r.size.height);
796 glOrtho(0, r.size.width, 0, r.size.height, -1, 1);
797 DEBUG_MSG_1(("OVIW(%p): frame[%i, %i, %i, %i]\n", (void*)self, (int)r.origin.x, (int)r.origin.x, (int)r.size.width, (int)r.size.height));
798 DEBUG_MSG_1(("OVIW(%p): m_Pos(%i,%i) m_Size(%i,%i)\n", (void*)self, (int)m_Pos.x, (int)m_Pos.y, (int)m_Size.width, (int)m_Size.height));
799 DEBUG_MSG_1(("OVIW(%p): m_RootShift(%i, %i)\n", (void*)self, (int)m_RootShift.x, (int)m_RootShift.y));
800 glMatrixMode(GL_TEXTURE);
801 glLoadIdentity();
802 glMatrixMode(GL_MODELVIEW);
803 glLoadIdentity();
804
805 /* Clear background to transparent */
806 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
807
808 DEBUG_MSG(("OVIW(%p): makeCurrent (non shared) %p\n", (void*)self, (void*)m_pGLCtx));
809 [m_pGLCtx makeCurrentContext];
810 }
811#endif
812}
813
814- (void)reshape
815{
816 NSRect parentFrame = NSZeroRect;
817 NSPoint parentPos = NSZeroPoint;
818 NSPoint childPos = NSZeroPoint;
819 NSRect childFrame = NSZeroRect;
820 NSRect newFrame = NSZeroRect;
821
822 DEBUG_MSG(("OVIW(%p): reshape\n", (void*)self));
823
824 /* Getting the right screen coordinates of the parents frame is a little bit
825 * complicated. */
826 parentFrame = [m_pParentView frame];
827 parentPos = [[m_pParentView window] convertBaseToScreen:[[m_pParentView superview] convertPointToBase:NSMakePoint(parentFrame.origin.x, parentFrame.origin.y + parentFrame.size.height)]];
828 parentFrame.origin.x = parentPos.x;
829 parentFrame.origin.y = parentPos.y;
830
831 /* Calculate the new screen coordinates of the overlay window. */
832 childPos = NSMakePoint(m_Pos.x, m_Pos.y + m_Size.height);
833 childPos = [[m_pParentView window] convertBaseToScreen:[[m_pParentView superview] convertPointToBase:childPos]];
834
835 /* Make a frame out of it. */
836 childFrame = NSMakeRect(childPos.x, childPos.y, m_Size.width, m_Size.height);
837
838 /* We have to make sure that the overlay window will not be displayed out
839 * of the parent window. So intersect both frames & use the result as the new
840 * frame for the window. */
841 newFrame = NSIntersectionRect(parentFrame, childFrame);
842
843 /* Later we have to correct the texture position in the case the window is
844 * out of the parents window frame. So save the shift values for later use. */
845 if (parentFrame.origin.x > childFrame.origin.x)
846 m_RootShift.x = parentFrame.origin.x - childFrame.origin.x;
847 else
848 m_RootShift.x = 0;
849 if (parentFrame.origin.y > childFrame.origin.y)
850 m_RootShift.y = parentFrame.origin.y - childFrame.origin.y;
851 else
852 m_RootShift.y = 0;
853
854 /*
855 NSScrollView *pScrollView = [[[m_pParentView window] contentView] enclosingScrollView];
856 if (pScrollView)
857 {
858 NSRect scrollRect = [pScrollView documentVisibleRect];
859 NSRect scrollRect = [m_pParentView visibleRect];
860 printf ("sc rect: %d %d %d %d\n", (int) scrollRect.origin.x,(int) scrollRect.origin.y,(int) scrollRect.size.width,(int) scrollRect.size.height);
861 NSRect b = [[m_pParentView superview] bounds];
862 printf ("bound rect: %d %d %d %d\n", (int) b.origin.x,(int) b.origin.y,(int) b.size.width,(int) b.size.height);
863 newFrame.origin.x += scrollRect.origin.x;
864 newFrame.origin.y += scrollRect.origin.y;
865 }
866 */
867
868 /* Set the new frame. */
869 [[self window] setFrame:newFrame display:YES];
870
871 /* Inform the dock tile view as well */
872 [self reshapeDockTile];
873
874 /* Make sure the context is updated according */
875 [self updateViewport];
876}
877
878- (void)createFBO
879{
880 GLint oldTexId = 0;
881 GLint oldFBId = 0;
882 NSView *pDockScreen = nil;
883 GLint maxTexSize = 0;
884 GLfloat imageAspectRatio = 0;
885 GLint filter = GL_NEAREST;
886
887 [self deleteFBO];
888
889#ifdef FBO
890 DEBUG_MSG(("OVIW(%p): createFBO\n", (void*)self));
891
892 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &oldTexId);
893 glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &oldFBId);
894
895 /* If not previously setup generate IDs for FBO and its associated texture. */
896 if (!m_FBOId)
897 {
898 /* Make sure the framebuffer extension is supported */
899 const GLubyte* strExt;
900 GLboolean isFBO;
901 /* Get the extension name string. It is a space-delimited list of the
902 * OpenGL extensions that are supported by the current renderer. */
903 strExt = glGetString(GL_EXTENSIONS);
904 isFBO = gluCheckExtension((const GLubyte*)"GL_EXT_framebuffer_object", strExt);
905 if (!isFBO)
906 {
907 DEBUG_MSG(("Your system does not support the GL_EXT_framebuffer_object extension\n"));
908 }
909 isFBO = gluCheckExtension((const GLubyte*)"GL_EXT_framebuffer_blit", strExt);
910 if (!isFBO)
911 {
912 DEBUG_MSG(("Your system does not support the GL_EXT_framebuffer_blit extension\n"));
913 }
914
915 /* Create FBO object */
916 glGenFramebuffersEXT(1, &m_FBOId);
917 /* & the texture as well the depth/stencil render buffer */
918 glGenTextures(1, &m_FBOTexBackId);
919 glGenTextures(1, &m_FBOTexFrontId);
920 DEBUG_MSG(("OVIW(%p): gen numbers: FBOId=%d FBOTexBackId=%d FBOTexFrontId=%d\n", (void*)self, m_FBOId, m_FBOTexBackId, m_FBOTexFrontId));
921
922 glGenRenderbuffersEXT(1, &m_FBODepthStencilPackedId);
923 }
924
925 m_FBOTexSize = m_Size;
926 /* Bind to FBO */
927 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FBOId);
928
929 /*
930 glEnable(GL_TEXTURE_RECTANGLE_ARB);
931 */
932
933 imageAspectRatio = m_FBOTexSize.width / m_FBOTexSize.height;
934
935 /* Sanity check against maximum OpenGL texture size. If bigger adjust to
936 * maximum possible size while maintain the aspect ratio. */
937 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize);
938 if (m_FBOTexSize.width > maxTexSize || m_FBOTexSize.height > maxTexSize)
939 {
940 filter = GL_LINEAR;
941 if (imageAspectRatio > 1)
942 {
943 m_FBOTexSize.width = maxTexSize;
944 m_FBOTexSize.height = maxTexSize / imageAspectRatio;
945 }
946 else
947 {
948 m_FBOTexSize.width = maxTexSize * imageAspectRatio;
949 m_FBOTexSize.height = maxTexSize;
950 }
951 }
952
953 DEBUG_MSG(("OVIW(%p): tex size is: %dx%d\n", (void*)self, (int)m_FBOTexSize.width, (int)m_FBOTexSize.height));
954
955 /* Initialize FBO Textures */
956 /* The GPUs like the GL_BGRA / GL_UNSIGNED_INT_8_8_8_8_REV combination
957 * others are also valid, but might incur a costly software translation. */
958 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_FBOTexBackId);
959 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);
960 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_FBOTexFrontId);
961 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);
962
963 /* Now attach the textures to the FBO as its color destinations */
964 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, m_FBOAttBackId, GL_TEXTURE_RECTANGLE_ARB, m_FBOTexBackId, 0);
965 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, m_FBOAttFrontId, GL_TEXTURE_RECTANGLE_ARB, m_FBOTexFrontId, 0);
966
967 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_FBODepthStencilPackedId);
968 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, m_FBOTexSize.width, m_FBOTexSize.height);
969 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_FBODepthStencilPackedId);
970
971 /* Bind the FBOs for reading and drawing. */
972 glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_FBOId);
973 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_FBOId);
974
975 /* Explicitly clear the textures otherwise they would contain old memory stuff. */
976 glDrawBuffer(m_FBOAttBackId);
977 glClear(GL_COLOR_BUFFER_BIT);
978 glDrawBuffer(m_FBOAttFrontId);
979 glClear(GL_COLOR_BUFFER_BIT);
980
981 /* Now initially reading/drawing to the back buffer. */
982 glReadBuffer(m_FBOAttBackId);
983 glDrawBuffer(m_FBOAttBackId);
984
985 /* Make sure the FBO was created successfully. */
986 if (GL_FRAMEBUFFER_COMPLETE_EXT != glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT))
987 DEBUG_MSG(("OVIW(%p): Framebuffer Object creation or update failed!\n", (void*)self));
988
989// glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
990 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, oldTexId);
991 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, (GLuint)oldFBId ? (GLuint)oldFBId : m_FBOId);
992
993 /* Is there a dock tile preview enabled in the GUI? If so setup a
994 * additional thumbnail view for the dock tile. */
995 pDockScreen = [self dockTileScreen];
996 if (pDockScreen)
997 {
998 if (!m_FBOThumbId)
999 {
1000 glGenFramebuffersEXT(1, &m_FBOThumbId);
1001 glGenTextures(1, &m_FBOThumbTexId);
1002 }
1003
1004 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FBOThumbId);
1005 /* Initialize FBO Texture */
1006 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_FBOThumbTexId);
1007 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1008 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1009 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP);
1010 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP);
1011
1012 /* The GPUs like the GL_BGRA / GL_UNSIGNED_INT_8_8_8_8_REV combination
1013 * others are also valid, but might incur a costly software translation. */
1014 glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, m_FBOTexSize.width * m_FBOThumbScaleX, m_FBOTexSize.height * m_FBOThumbScaleY, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
1015
1016 /* Now attach texture to the FBO as its color destination */
1017 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, m_FBOThumbTexId, 0);
1018
1019 /* Make sure the FBO was created successfully. */
1020 if (GL_FRAMEBUFFER_COMPLETE_EXT != glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT))
1021 DEBUG_MSG(("OVIW(%p): Framebuffer \"Thumb\" Object creation or update failed!\n", (void*)self));
1022
1023 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, oldTexId);
1024 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, (GLuint)oldFBId ? (GLuint)oldFBId : m_FBOId);
1025
1026 m_DockTileView = [[DockOverlayView alloc] init];
1027 [self reshapeDockTile];
1028 [pDockScreen addSubview:m_DockTileView];
1029 }
1030
1031 /* Initialize with one big visual region over the full size */
1032 [self clearVisibleRegions];
1033 m_cClipRects = 1;
1034 m_paClipRects = (GLint*)RTMemAlloc(sizeof(GLint) * 4);
1035 m_paClipRects[0] = 0;
1036 m_paClipRects[1] = 0;
1037 m_paClipRects[2] = m_FBOTexSize.width;
1038 m_paClipRects[3] = m_FBOTexSize.height;
1039#endif
1040}
1041
1042- (void)deleteFBO
1043{
1044 DEBUG_MSG(("OVIW(%p): deleteFBO\n", (void*)self));
1045
1046 if (m_pSharedGLCtx)
1047 {
1048 DEBUG_MSG(("OVIW(%p): makeCurrent (shared) %p\n", (void*)self, (void*)m_pSharedGLCtx));
1049 [m_pSharedGLCtx makeCurrentContext];
1050 [m_pSharedGLCtx update];
1051
1052 glEnable(GL_TEXTURE_RECTANGLE_ARB);
1053 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
1054 }
1055
1056 if (m_pGLCtx)
1057 {
1058 DEBUG_MSG(("OVIW(%p): makeCurrent (non shared) %p\n", (void*)self, (void*)m_pGLCtx));
1059 [m_pGLCtx makeCurrentContext];
1060
1061#ifdef FBO
1062 if (m_FBODepthStencilPackedId > 0)
1063 {
1064 glDeleteRenderbuffersEXT(1, &m_FBODepthStencilPackedId);
1065 m_FBODepthStencilPackedId = 0;
1066 }
1067 if (m_FBOTexBackId > 0)
1068 {
1069 glDeleteTextures(1, &m_FBOTexBackId);
1070 m_FBOTexBackId = 0;
1071 }
1072 if (m_FBOTexFrontId > 0)
1073 {
1074 glDeleteTextures(1, &m_FBOTexFrontId);
1075 m_FBOTexFrontId = 0;
1076 }
1077 if (m_FBOId > 0)
1078 {
1079 if ([self isCurrentFBO])
1080 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1081
1082 glDeleteFramebuffersEXT(1, &m_FBOId);
1083 m_FBOId = 0;
1084 }
1085#endif
1086 }
1087
1088 if (m_DockTileView != nil)
1089 {
1090 [m_DockTileView removeFromSuperview];
1091 [m_DockTileView release];
1092 m_DockTileView = nil;
1093 }
1094}
1095
1096- (void)updateFBO
1097{
1098 DEBUG_MSG(("OVIW(%p): updateFBO\n", (void*)self));
1099
1100 [self makeCurrentFBO];
1101
1102 if (m_pGLCtx)
1103 {
1104#ifdef FBO
1105 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1106 [self createFBO];
1107 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FBOId);
1108#endif
1109 [m_pGLCtx update];
1110 }
1111}
1112
1113- (void)makeCurrentFBO
1114{
1115 DEBUG_MSG(("OVIW(%p): makeCurrentFBO\n", (void*)self));
1116
1117#ifdef FBO
1118 DEBUG_MSG(("OVIW(%p): FBOId=%d CTX=%p\n", (void*)self, m_FBOId, (void*)m_pGLCtx));
1119 if([NSOpenGLContext currentContext] != 0)
1120 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FBOId);
1121#endif
1122 if (m_pGLCtx)
1123 {
1124 if ([m_pGLCtx view] != self)
1125 {
1126 /* We change the active view, so flush first */
1127 if([NSOpenGLContext currentContext] != 0)
1128 glFlush();
1129 [m_pGLCtx setView: self];
1130 CHECK_GL_ERROR();
1131 }
1132 /*
1133 if ([NSOpenGLContext currentContext] != m_pGLCtx)
1134 */
1135 {
1136 [m_pGLCtx makeCurrentContext];
1137 CHECK_GL_ERROR();
1138 /*
1139 [m_pGLCtx update];
1140 */
1141 }
1142 }
1143#ifdef FBO
1144 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FBOId);
1145#endif
1146}
1147
1148- (bool)isCurrentFBO
1149{
1150#ifdef FBO
1151 GLint curFBOId = 0;
1152
1153 glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &curFBOId);
1154 DEBUG_MSG_1(("OVIW(%p): isCurrentFBO: curFBOId=%d FBOId=%d\n", (void*)self, curFBOId, m_FBOId));
1155 return (GLuint)curFBOId == m_FBOId;
1156#else
1157 return false;
1158#endif
1159}
1160
1161- (void)tryDraw
1162{
1163 if ([self lockFocusIfCanDraw])
1164 {
1165 [self renderFBOToView];
1166 [self unlockFocus];
1167 }
1168}
1169
1170- (void)swapFBO
1171{
1172 GLint sw = 0;
1173 GLint readFBOId = 0;
1174 GLint drawFBOId = 0;
1175 GLint readId = 0;
1176 GLint drawId = 0;
1177
1178 DEBUG_MSG(("OVIW(%p): swapFBO\n", (void*)self));
1179
1180#ifdef FBO
1181 /* Don't use flush buffers cause we are using FBOs here! */
1182
1183 /* Before we swap make sure everything is done (This is really
1184 * important. Don't remove.) */
1185 glFlush();
1186
1187 /* Fetch the current used read and draw buffers. */
1188 glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &readFBOId);
1189 glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &drawFBOId);
1190 glGetIntegerv(GL_READ_BUFFER, &readId);
1191 glGetIntegerv(GL_DRAW_BUFFER, &drawId);
1192
1193 /* Do the swapping of our internal ids */
1194 sw = m_FBOTexFrontId;
1195 m_FBOTexFrontId = m_FBOTexBackId;
1196 m_FBOTexBackId = sw;
1197 sw = m_FBOAttFrontId;
1198 m_FBOAttFrontId = m_FBOAttBackId;
1199 m_FBOAttBackId = sw;
1200
1201 DEBUG_MSG_1(("read FBO: %d draw FBO: %d readId: %d drawId: %d\n", readFBOId, drawFBOId, readId, drawId));
1202 /* We also have to swap the real ids on the current context. */
1203 if ((GLuint)readFBOId == m_FBOId)
1204 {
1205 if ((GLuint)readId == m_FBOAttFrontId)
1206 glReadBuffer(m_FBOAttBackId);
1207 if ((GLuint)readId == m_FBOAttBackId)
1208 glReadBuffer(m_FBOAttFrontId);
1209 }
1210 if ((GLuint)drawFBOId == m_FBOId)
1211 {
1212 if ((GLuint)drawId == m_FBOAttFrontId)
1213 glDrawBuffer(m_FBOAttBackId);
1214 if ((GLuint)drawId == m_FBOAttBackId)
1215 glDrawBuffer(m_FBOAttFrontId);
1216 }
1217
1218 [self tryDraw];
1219#else
1220 [m_pGLCtx flushBuffer];
1221#endif
1222}
1223
1224- (void)flushFBO
1225{
1226 GLint drawId = 0;
1227 GLint FBOId = 0;
1228
1229 DEBUG_MSG(("OVIW(%p): flushFBO\n", (void*)self));
1230
1231 glFlush();
1232#ifdef FBO
1233 /* If at any time OpenGl operations where done in the front buffer, we need
1234 * to reflect this in the FBO as well. This is something which on real
1235 * hardware happens and unfortunately some applications rely on it (grrr ... Compiz). */
1236 if ( m_fFrontDrawing
1237 && [self isCurrentFBO])
1238 {
1239 /* Only reset if we aren't currently front. */
1240 glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &FBOId);
1241 glGetIntegerv(GL_DRAW_BUFFER, &drawId);
1242 if (!( (GLuint)FBOId == m_FBOId
1243 && (GLuint)drawId == m_FBOAttFrontId))
1244 m_fFrontDrawing = false;
1245 [self tryDraw];
1246 }
1247#endif
1248}
1249
1250- (void)finishFBO
1251{
1252 DEBUG_MSG(("OVIW(%p): finishFBO\n", (void*)self));
1253
1254 glFinish();
1255#ifdef FBO
1256 if ([self isCurrentFBO])
1257 [self tryDraw];
1258#endif
1259}
1260
1261- (void)stateInfo:(GLenum)pname withParams:(GLint*)params
1262{
1263 GLint test;
1264// DEBUG_MSG_1(("StateInfo requested: %d\n", pname));
1265
1266 glGetIntegerv(pname, params);
1267#ifdef FBO
1268 switch(pname)
1269 {
1270 case GL_FRAMEBUFFER_BINDING_EXT:
1271 case GL_READ_FRAMEBUFFER_BINDING:
1272 case GL_READ_FRAMEBUFFER_EXT:
1273 case GL_DRAW_FRAMEBUFFER_EXT:
1274 {
1275 if ((GLuint)*params == m_FBOId)
1276 *params = 0;
1277 break;
1278 }
1279 case GL_READ_BUFFER:
1280 {
1281 glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &test);
1282 if ((GLuint)test == m_FBOId)
1283 {
1284 if ((GLuint)*params == m_FBOAttFrontId)
1285 *params = GL_FRONT;
1286 else
1287 if ((GLuint)*params == m_FBOAttBackId)
1288 *params = GL_BACK;
1289 }
1290 break;
1291 }
1292 case GL_DRAW_BUFFER:
1293 {
1294 glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &test);
1295 if ((GLuint)test == m_FBOId)
1296 {
1297 if ((GLuint)*params == m_FBOAttFrontId)
1298 *params = GL_FRONT;
1299 else
1300 if ((GLuint)*params == m_FBOAttBackId)
1301 *params = GL_BACK;
1302 }
1303 break;
1304 }
1305 }
1306#endif
1307}
1308
1309- (void)readBuffer:(GLenum)mode
1310{
1311#ifdef FBO
1312 /*
1313 if ([self isCurrentFBO])
1314 */
1315 {
1316 if (mode == GL_FRONT)
1317 {
1318 glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_FBOId);
1319 glReadBuffer(m_FBOAttFrontId);
1320 }
1321 else if (mode == GL_BACK)
1322 {
1323 glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_FBOId);
1324 glReadBuffer(m_FBOAttBackId);
1325 }
1326 else
1327 glReadBuffer(mode);
1328 }
1329#else
1330 glReadBuffer(mode);
1331#endif
1332}
1333
1334- (void)drawBuffer:(GLenum)mode
1335{
1336#ifdef FBO
1337 /*
1338 if ([self isCurrentFBO])
1339 */
1340 {
1341 if (mode == GL_FRONT)
1342 {
1343 DEBUG_MSG(("OVIW(%p): front\n", (void*)self));
1344 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_FBOId);
1345 glDrawBuffer(m_FBOAttFrontId);
1346 m_fFrontDrawing = true;
1347 }
1348 else if (mode == GL_BACK)
1349 {
1350 DEBUG_MSG(("OVIW(%p): back\n", (void*)self));
1351 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_FBOId);
1352 glDrawBuffer(m_FBOAttBackId);
1353 }
1354 else
1355 {
1356 DEBUG_MSG(("OVIW(%p): other: %d\n", (void*)self, mode));
1357 glDrawBuffer(mode);
1358 }
1359 }
1360#else
1361 glDrawBuffer(mode);
1362#endif
1363}
1364
1365- (void)bindFBO:(GLenum)target withFrameBuffer:(GLuint)framebuffer
1366{
1367#ifdef FBO
1368 if (framebuffer != 0)
1369 glBindFramebufferEXT(target, framebuffer);
1370 else
1371 glBindFramebufferEXT(target, m_FBOId);
1372#else
1373 glBindFramebufferEXT(target, framebuffer);
1374#endif
1375}
1376
1377- (void)renderFBOToView
1378{
1379 GLint opaque = 0;
1380 GLint i = 0;
1381 GLint oldReadFBOId = 0;
1382 GLint oldDrawFBOId = 0;
1383 GLint oldReadId = 0;
1384 GLint oldDrawId = 0;
1385
1386 DEBUG_MSG(("OVIW(%p): renderFBOToView\n", (void*)self));
1387
1388#ifdef FBO
1389
1390 /* Fetch the current used read and draw buffers. */
1391 glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING_EXT, &oldReadFBOId);
1392 glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING_EXT, &oldDrawFBOId);
1393 glGetIntegerv(GL_READ_BUFFER, &oldReadId);
1394 glGetIntegerv(GL_DRAW_BUFFER, &oldDrawId);
1395
1396 if (!m_pSharedGLCtx)
1397 {
1398 /* Create a shared context out of the main context. Use the same pixel format. */
1399 m_pSharedGLCtx = [[NSOpenGLContext alloc] initWithFormat:[(OverlayOpenGLContext*)m_pGLCtx openGLPixelFormat] shareContext:m_pGLCtx];
1400
1401 /* Set the new context as non opaque */
1402 [m_pSharedGLCtx setValues:&opaque forParameter:NSOpenGLCPSurfaceOpacity];
1403 /* Set this view as the drawable for the new context */
1404 [m_pSharedGLCtx setView: self];
1405 [self updateViewport];
1406 }
1407
1408 if (m_pSharedGLCtx)
1409 {
1410 NSRect r = [self frame];
1411 DEBUG_MSG(("OVIW(%p): rF2V frame: [%i, %i, %i, %i]\n", (void*)self, (int)r.origin.x, (int)r.origin.y, (int)r.size.width, (int)r.size.height));
1412
1413 if (m_FBOTexFrontId > 0)
1414 {
1415 if ([m_pSharedGLCtx view] != self)
1416 {
1417 DEBUG_MSG(("OVIW(%p): not current view of shared ctx! Switching ...\n", (void*)self));
1418 [m_pSharedGLCtx setView: self];
1419 [self updateViewport];
1420 }
1421
1422 [m_pSharedGLCtx makeCurrentContext];
1423
1424 glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_FBOId);
1425 glReadBuffer(m_FBOAttFrontId);
1426 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
1427 glDrawBuffer(GL_BACK);
1428
1429 /* Render FBO content to the dock tile when necessary. */
1430 [self renderFBOToDockTile];
1431
1432#if 1 /* Set to 0 to see the docktile instead of the real output */
1433 /* Clear background to transparent */
1434 glClear(GL_COLOR_BUFFER_BIT);
1435
1436 /* Blit the content of the FBO to the screen. */
1437 for (i = 0; i < m_cClipRects; ++i)
1438 {
1439 GLint x1 = m_paClipRects[4*i];
1440 GLint y1 = r.size.height - m_paClipRects[4*i+1];
1441 GLint x2 = m_paClipRects[4*i+2];
1442 GLint y2 = r.size.height - m_paClipRects[4*i+3];
1443 glBlitFramebufferEXT(x1, y1 + m_RootShift.y, x2, y2 + m_RootShift.y,
1444 x1 - m_RootShift.x, y1, x2 - m_RootShift.x, y2,
1445 GL_COLOR_BUFFER_BIT, GL_NEAREST);
1446 }
1447#endif
1448 /*
1449 glFinish();
1450 */
1451 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1452 [m_pSharedGLCtx flushBuffer];
1453
1454 [m_pGLCtx makeCurrentContext];
1455 /* Reset to previous buffer bindings. */
1456 glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, oldReadFBOId);
1457 glReadBuffer(oldReadId);
1458 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, oldDrawFBOId);
1459 glDrawBuffer(oldDrawId);
1460 }
1461 }
1462#else
1463 [m_pGLCtx flushBuffer];
1464#endif
1465}
1466
1467- (void)renderFBOToDockTile
1468{
1469 NSRect r = [self frame];
1470 NSRect rr = NSZeroRect;
1471 GLint i = 0;
1472 NSDockTile *pDT = nil;
1473
1474#ifdef FBO
1475 if ( m_FBOThumbId
1476 && m_FBOThumbTexId
1477 && [m_DockTileView thumbBitmap] != nil)
1478 {
1479 /* Only update after at least 200 ms, cause glReadPixels is
1480 * heavy performance wise. */
1481 uint64_t uiNewTime = RTTimeMilliTS();
1482 if (uiNewTime - m_uiDockUpdateTime > 200)
1483 {
1484 m_uiDockUpdateTime = uiNewTime;
1485#if 0
1486 /* todo: check this for optimization */
1487 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, myTextureName);
1488 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_STORAGE_HINT_APPLE,
1489 GL_STORAGE_SHARED_APPLE);
1490 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1491 glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA,
1492 sizex, sizey, 0, GL_BGRA,
1493 GL_UNSIGNED_INT_8_8_8_8_REV, myImagePtr);
1494 glCopyTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB,
1495 0, 0, 0, 0, 0, image_width, image_height);
1496 glFlush();
1497 /* Do other work processing here, using a double or triple buffer */
1498 glGetTexImage(GL_TEXTURE_RECTANGLE_ARB, 0, GL_BGRA,
1499 GL_UNSIGNED_INT_8_8_8_8_REV, pixels);
1500#endif
1501 /* Clear background to transparent */
1502 glClear(GL_COLOR_BUFFER_BIT);
1503
1504 rr = [m_DockTileView frame];
1505
1506 for (i = 0; i < m_cClipRects; ++i)
1507 {
1508 GLint x1 = m_paClipRects[4*i];
1509 GLint y1 = r.size.height - m_paClipRects[4*i+1];
1510 GLint x2 = m_paClipRects[4*i+2];
1511 GLint y2 = r.size.height - m_paClipRects[4*i+3];
1512
1513 glBlitFramebufferEXT(x1, y1 + m_RootShift.y, x2, y2 + m_RootShift.y,
1514 x1 * m_FBOThumbScaleX, y1 * m_FBOThumbScaleY, x2 * m_FBOThumbScaleX, y2 * m_FBOThumbScaleY,
1515 GL_COLOR_BUFFER_BIT, GL_LINEAR);
1516 }
1517 glFinish();
1518
1519 glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
1520 glReadBuffer(GL_BACK);
1521 /* Here the magic of reading the FBO content in our own buffer
1522 * happens. We have to lock this access, in the case the dock
1523 * is updated currently. */
1524 [m_DockTileView lock];
1525 glReadPixels(0, 0, rr.size.width, rr.size.height,
1526 GL_BGRA,
1527 GL_UNSIGNED_INT_8_8_8_8,
1528 [[m_DockTileView thumbBitmap] bitmapData]);
1529 [m_DockTileView unlock];
1530
1531 glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_FBOId);
1532 glReadBuffer(m_FBOAttFrontId);
1533
1534 pDT = [[NSApplication sharedApplication] dockTile];
1535
1536 /* Send a display message to the dock tile in the main thread */
1537 [[[NSApplication sharedApplication] dockTile] performSelectorOnMainThread:@selector(display) withObject:nil waitUntilDone:NO];
1538
1539 }
1540 }
1541#endif
1542}
1543
1544- (void)clearVisibleRegions
1545{
1546 if(m_paClipRects)
1547 {
1548 RTMemFree(m_paClipRects);
1549 m_paClipRects = NULL;
1550 }
1551 m_cClipRects = 0;
1552}
1553
1554- (void)setVisibleRegions:(GLint)cRects paRects:(GLint*)paRects
1555{
1556 DEBUG_MSG_1(("OVIW(%p): setVisibleRegions: cRects=%d\n", (void*)self, cRects));
1557
1558 [self clearVisibleRegions];
1559
1560 if (cRects > 0)
1561 {
1562#ifdef DEBUG_poetzsch
1563 int i =0;
1564 for (i = 0; i < cRects; ++i)
1565 DEBUG_MSG_1(("OVIW(%p): setVisibleRegions: %d - %d %d %d %d\n", (void*)self, i, paRects[i * 4], paRects[i * 4 + 1], paRects[i * 4 + 2], paRects[i * 4 + 3]));
1566#endif
1567
1568 m_paClipRects = (GLint*)RTMemAlloc(sizeof(GLint) * 4 * cRects);
1569 m_cClipRects = cRects;
1570 memcpy(m_paClipRects, paRects, sizeof(GLint) * 4 * cRects);
1571 }
1572 else
1573 [self tryDraw];
1574}
1575
1576- (NSView*)dockTileScreen
1577{
1578 NSView *contentView = [[[NSApplication sharedApplication] dockTile] contentView];
1579 NSView *screenContent = nil;
1580 /* First try the new variant which checks if this window is within the
1581 screen which is previewed in the dock. */
1582 if ([contentView respondsToSelector:@selector(screenContentWithParentView:)])
1583 screenContent = [contentView performSelector:@selector(screenContentWithParentView:) withObject:(id)m_pParentView];
1584 /* If it fails, fall back to the old variant (VBox...) */
1585 else if ([contentView respondsToSelector:@selector(screenContent)])
1586 screenContent = [contentView performSelector:@selector(screenContent)];
1587 return screenContent;
1588}
1589
1590- (void)reshapeDockTile
1591{
1592 NSRect newFrame = NSZeroRect;
1593
1594 NSView *pView = [self dockTileScreen];
1595 if (pView != nil)
1596 {
1597 NSRect dockFrame = [pView frame];
1598 NSRect parentFrame = [m_pParentView frame];
1599
1600 m_FBOThumbScaleX = (float)dockFrame.size.width / parentFrame.size.width;
1601 m_FBOThumbScaleY = (float)dockFrame.size.height / parentFrame.size.height;
1602 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));
1603 /*
1604 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));
1605 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));
1606 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);
1607 */
1608 [m_DockTileView setFrame: newFrame];
1609 }
1610}
1611
1612@end
1613
1614/********************************************************************************
1615*
1616* OpenGL context management
1617*
1618********************************************************************************/
1619void cocoaGLCtxCreate(NativeNSOpenGLContextRef *ppCtx, GLbitfield fVisParams)
1620{
1621 NSOpenGLPixelFormat *pFmt = nil;
1622
1623 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1624
1625 NSOpenGLPixelFormatAttribute attribs[24] =
1626 {
1627 NSOpenGLPFAWindow,
1628 NSOpenGLPFAAccelerated,
1629 NSOpenGLPFAColorSize, (NSOpenGLPixelFormatAttribute)24
1630 };
1631
1632 int i = 4;
1633
1634 if (fVisParams & CR_ALPHA_BIT)
1635 {
1636 DEBUG_MSG(("CR_ALPHA_BIT requested\n"));
1637 attribs[i++] = NSOpenGLPFAAlphaSize;
1638 attribs[i++] = 8;
1639 }
1640 if (fVisParams & CR_DEPTH_BIT)
1641 {
1642 DEBUG_MSG(("CR_DEPTH_BIT requested\n"));
1643 attribs[i++] = NSOpenGLPFADepthSize;
1644 attribs[i++] = 24;
1645 }
1646 if (fVisParams & CR_STENCIL_BIT)
1647 {
1648 DEBUG_MSG(("CR_STENCIL_BIT requested\n"));
1649 attribs[i++] = NSOpenGLPFAStencilSize;
1650 attribs[i++] = 8;
1651 }
1652 if (fVisParams & CR_ACCUM_BIT)
1653 {
1654 DEBUG_MSG(("CR_ACCUM_BIT requested\n"));
1655 attribs[i++] = NSOpenGLPFAAccumSize;
1656 if (fVisParams & CR_ALPHA_BIT)
1657 attribs[i++] = 32;
1658 else
1659 attribs[i++] = 24;
1660 }
1661 if (fVisParams & CR_MULTISAMPLE_BIT)
1662 {
1663 DEBUG_MSG(("CR_MULTISAMPLE_BIT requested\n"));
1664 attribs[i++] = NSOpenGLPFASampleBuffers;
1665 attribs[i++] = 1;
1666 attribs[i++] = NSOpenGLPFASamples;
1667 attribs[i++] = 4;
1668 }
1669 if (fVisParams & CR_DOUBLE_BIT)
1670 {
1671 DEBUG_MSG(("CR_DOUBLE_BIT requested\n"));
1672 attribs[i++] = NSOpenGLPFADoubleBuffer;
1673 }
1674 if (fVisParams & CR_STEREO_BIT)
1675 {
1676 /* We don't support that.
1677 DEBUG_MSG(("CR_STEREO_BIT requested\n"));
1678 attribs[i++] = NSOpenGLPFAStereo;
1679 */
1680 }
1681
1682 /* Mark the end */
1683 attribs[i++] = 0;
1684
1685 /* Choose a pixel format */
1686 pFmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
1687
1688 if (pFmt)
1689 {
1690 *ppCtx = [[OverlayOpenGLContext alloc] initWithFormat:pFmt shareContext:nil];
1691
1692 /* Enable multi threaded OpenGL engine */
1693 /*
1694 CGLContextObj cglCtx = [*ppCtx CGLContextObj];
1695 CGLError err = CGLEnable(cglCtx, kCGLCEMPEngine);
1696 if (err != kCGLNoError)
1697 printf ("Couldn't enable MT OpenGL engine!\n");
1698 */
1699
1700 DEBUG_MSG(("New context %X\n", (uint)*ppCtx));
1701 }
1702
1703 [pPool release];
1704}
1705
1706void cocoaGLCtxDestroy(NativeNSOpenGLContextRef pCtx)
1707{
1708 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1709
1710 /*
1711 [pCtx release];
1712 */
1713
1714 [pPool release];
1715}
1716
1717/********************************************************************************
1718*
1719* View management
1720*
1721********************************************************************************/
1722void cocoaViewCreate(NativeNSViewRef *ppView, NativeNSViewRef pParentView, GLbitfield fVisParams)
1723{
1724 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1725
1726 /* Create our worker view */
1727 OverlayView* pView = [[OverlayView alloc] initWithFrame:NSZeroRect thread:RTThreadSelf() parentView:pParentView];
1728
1729 if (pView)
1730 {
1731 /* We need a real window as container for the view */
1732 [[OverlayWindow alloc] initWithParentView:pParentView overlayView:pView];
1733 /* Return the freshly created overlay view */
1734 *ppView = pView;
1735 }
1736
1737 [pPool release];
1738}
1739
1740void cocoaViewReparent(NativeNSViewRef pView, NativeNSViewRef pParentView)
1741{
1742 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1743
1744 OverlayView* pOView = (OverlayView*)pView;
1745
1746 if (pOView)
1747 {
1748 /* Make sure the window is removed from any previous parent window. */
1749 if ([[pOView overlayWin] parentWindow] != nil)
1750 {
1751 [[[pOView overlayWin] parentWindow] removeChildWindow:[pOView overlayWin]];
1752 }
1753
1754 /* Set the new parent view */
1755 [pOView setParentView: pParentView];
1756
1757 /* Add the overlay window as a child to the new parent window */
1758 if (pParentView != nil)
1759 {
1760 [[pParentView window] addChildWindow:[pOView overlayWin] ordered:NSWindowAbove];
1761 [pOView createFBO];
1762 }
1763 }
1764
1765 [pPool release];
1766}
1767
1768void cocoaViewDestroy(NativeNSViewRef pView)
1769{
1770 NSWindow *pWin = nil;
1771
1772 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1773
1774 /* Hide the view early */
1775 [pView setHidden: YES];
1776
1777 pWin = [pView window];
1778 [[NSNotificationCenter defaultCenter] removeObserver:pWin];
1779 [pWin setContentView: nil];
1780 [[pWin parentWindow] removeChildWindow: pWin];
1781 /*
1782 a = [pWin retainCount];
1783 for (; a > 1; --a)
1784 [pWin performSelector:@selector(release)]
1785 */
1786 [pWin performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:YES];
1787 /*
1788 [pWin release];
1789 */
1790
1791 /* There seems to be a bug in the performSelector method which is called in
1792 * parentWindowChanged above. The object is retained but not released. This
1793 * results in an unbalanced reference count, which is here manually
1794 * decremented. */
1795 /*
1796 a = [pView retainCount];
1797 for (; a > 1; --a)
1798 */
1799 [pView performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:YES];
1800 /*
1801 [pView release];
1802 */
1803
1804 [pPool release];
1805}
1806
1807void cocoaViewShow(NativeNSViewRef pView, GLboolean fShowIt)
1808{
1809 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1810
1811 [pView setHidden: fShowIt==GL_TRUE?NO:YES];
1812
1813 [pPool release];
1814}
1815
1816void cocoaViewDisplay(NativeNSViewRef pView)
1817{
1818 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1819
1820 DEBUG_MSG_1(("cocoaViewDisplay %p\n", (void*)pView));
1821 [(OverlayView*)pView swapFBO];
1822
1823 [pPool release];
1824
1825}
1826
1827void cocoaViewSetPosition(NativeNSViewRef pView, NativeNSViewRef pParentView, int x, int y)
1828{
1829 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1830
1831 [(OverlayView*)pView setPos:NSMakePoint(x, y)];
1832
1833 [pPool release];
1834}
1835
1836void cocoaViewSetSize(NativeNSViewRef pView, int w, int h)
1837{
1838 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1839
1840 [(OverlayView*)pView setSize:NSMakeSize(w, h)];
1841
1842 [pPool release];
1843}
1844
1845void cocoaViewGetGeometry(NativeNSViewRef pView, int *pX, int *pY, int *pW, int *pH)
1846{
1847 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1848
1849 NSRect frame = [[pView window] frame];
1850 *pX = frame.origin.x;
1851 *pY = frame.origin.y;
1852 *pW = frame.size.width;
1853 *pH = frame.size.height;
1854
1855 [pPool release];
1856}
1857
1858void cocoaViewMakeCurrentContext(NativeNSViewRef pView, NativeNSOpenGLContextRef pCtx)
1859{
1860 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1861
1862 DEBUG_MSG(("cocoaViewMakeCurrentContext(%p, %p)\n", (void*)pView, (void*)pCtx));
1863
1864 [(OverlayView*)pView setGLCtx:pCtx];
1865 [(OverlayView*)pView makeCurrentFBO];
1866
1867 [pPool release];
1868}
1869
1870void cocoaViewSetVisibleRegion(NativeNSViewRef pView, GLint cRects, GLint* paRects)
1871{
1872 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1873
1874 [(OverlayView*)pView setVisibleRegions:cRects paRects:paRects];
1875
1876 [pPool release];
1877}
1878
1879/********************************************************************************
1880*
1881* Additional OpenGL wrapper
1882*
1883********************************************************************************/
1884static void performSelectorOnView(SEL selector)
1885{
1886 NSOpenGLContext *pCtx = [NSOpenGLContext currentContext];
1887
1888 if (pCtx)
1889 {
1890 NSView *pView = [pCtx view];
1891 if (pView)
1892 {
1893 if ([pView respondsToSelector:selector])
1894 [pView performSelector:selector];
1895 }
1896 }
1897}
1898
1899static void performSelectorOnViewOneArg(SEL selector, id arg1)
1900{
1901 NSOpenGLContext *pCtx = [NSOpenGLContext currentContext];
1902
1903 if (pCtx)
1904 {
1905 NSView *pView = [pCtx view];
1906 if (pView)
1907 {
1908 if ([pView respondsToSelector:selector])
1909 [pView performSelector:selector withObject:arg1];
1910 }
1911 }
1912}
1913
1914static void performSelectorOnViewTwoArgs(SEL selector, id arg1, id arg2)
1915{
1916 NSOpenGLContext *pCtx = [NSOpenGLContext currentContext];
1917
1918 if (pCtx)
1919 {
1920 NSView *pView = [pCtx view];
1921 if (pView)
1922 {
1923 if ([pView respondsToSelector:selector])
1924 [pView performSelector:selector withObject:arg1 withObject:arg2];
1925 }
1926 }
1927}
1928
1929void cocoaFlush(void)
1930{
1931 NSOpenGLContext *pCtx = nil;
1932
1933 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1934
1935 DEBUG_MSG_1(("glFlush called\n"));
1936
1937 performSelectorOnView(@selector(flushFBO));
1938
1939 [pPool release];
1940}
1941
1942void cocoaFinish(void)
1943{
1944 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1945
1946 DEBUG_MSG_1(("glFinish called\n"));
1947
1948 performSelectorOnView(@selector(finishFBO));
1949
1950 [pPool release];
1951}
1952
1953void cocoaBindFramebufferEXT(GLenum target, GLuint framebuffer)
1954{
1955 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1956
1957 DEBUG_MSG_1(("glBindFramebufferEXT called target: %d fb: %d\n", target, framebuffer));
1958
1959 performSelectorOnViewTwoArgs(@selector(bindFBO:withFrameBuffer:), (id)target, (id)framebuffer);
1960
1961 [pPool release];
1962}
1963
1964void cocoaCopyPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type)
1965{
1966 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1967 GLbitfield mask = GL_COLOR_BUFFER_BIT;
1968
1969 DEBUG_MSG_1(("glCopyPixels called: %d,%d-%dx%d type: %d\n", x, y, width, height, type));
1970
1971#ifdef FBO
1972 if (type == GL_DEPTH)
1973 mask = GL_DEPTH_BUFFER_BIT;
1974 else if (type == GL_STENCIL)
1975 mask = GL_STENCIL_BUFFER_BIT;
1976 glBlitFramebufferEXT(x, y, x + width, y + height, x, y, x + width, y + height, mask, GL_NEAREST);
1977#else
1978 glCopyPixels(x, y, width, height, type);
1979#endif
1980
1981 [pPool release];
1982}
1983
1984void cocoaGetIntegerv(GLenum pname, GLint *params)
1985{
1986 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1987
1988// DEBUG_MSG_1(("getIntergerv called: %d\n", pname));
1989
1990 performSelectorOnViewTwoArgs(@selector(stateInfo:withParams:), (id)pname, (id)params);
1991
1992 [pPool release];
1993}
1994
1995void cocoaReadBuffer(GLenum mode)
1996{
1997 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1998
1999 DEBUG_MSG_1(("glReadBuffer called: %d\n", mode));
2000
2001 performSelectorOnViewOneArg(@selector(readBuffer:), (id)mode);
2002
2003 [pPool release];
2004}
2005
2006void cocoaDrawBuffer(GLenum mode)
2007{
2008 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
2009
2010 DEBUG_MSG_1(("glDrawBuffer called: %d\n", mode));
2011
2012 performSelectorOnViewOneArg(@selector(drawBuffer:), (id)mode);
2013
2014 [pPool release];
2015}
2016
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