VirtualBox

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

Last change on this file since 45066 was 45066, checked in by vboxsync, 12 years ago

crOpenGL: misc bugfixes & cleanups

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