VirtualBox

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

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

crOpenGL: host 3d window repaint impl for Win host; enable offscreen rendering for Win; 3D window repaint generics

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