VirtualBox

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

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

crOpenGL: fix 2D crash on shutdown

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