VirtualBox

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

Last change on this file since 48429 was 48348, checked in by vboxsync, 11 years ago

crOpenGL: int gl version presentation

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

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