VirtualBox

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

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

OpenGL-OSX: no alpha for the target

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

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