VirtualBox

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

最後變更 在這個檔案從37332是 37332,由 vboxsync 提交於 14 年 前

OpenGl-OSX: introduce double buffer support for FBO (Gnome3 fix); use glBlitFramebufferEXT for drawing; cleanup

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

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