VirtualBox

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

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

crOpenGL/OSX: synch window reshape

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