VirtualBox

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

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

crOpenGL/osx: fix visible regions handling

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 50.4 KB
Line 
1/* $Id: renderspu_cocoa_helper.m 45048 2013-03-15 09:54:00Z 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 {
1099 if ([m_pSharedGLCtx view] != self)
1100 {
1101 DEBUG_MSG(("OVIW(%p): not current view of shared ctx! Switching ...\n", (void*)self));
1102 [m_pSharedGLCtx setView: self];
1103 m_fNeedViewportUpdate = true;
1104 }
1105
1106 if (m_fNeedViewportUpdate)
1107 {
1108 [self updateViewportCS];
1109 m_fNeedViewportUpdate = false;
1110 }
1111
1112 /* Render FBO content to the dock tile when necessary. */
1113 [self vboxPresentToDockTileCS];
1114
1115 [self vboxPresentToViewCS];
1116 }
1117}
1118
1119- (void)vboxPresentToViewCS
1120{
1121 NSRect r = [self frame];
1122 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));
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 < cRegions; ++i)
1150 {
1151 const RTRECT * pSrcRect = &paSrcRegions[i];
1152 const RTRECT * pDstRect = &paDstRegions[i];
1153 GLint srcY1 = r.size.height - pSrcRect->yTop;
1154 GLint srcY2 = r.size.height - pSrcRect->yBottom;
1155 GLint dstY1 = r.size.height - pDstRect->yTop;
1156 GLint dstY2 = r.size.height - pDstRect->yBottom;
1157
1158 glBlitFramebufferEXT(pSrcRect->xLeft, srcY1 + m_RootShift.y,
1159 pSrcRect->xRight, srcY2 + m_RootShift.y,
1160 pDstRect->xLeft - m_RootShift.x, dstY1,
1161 pDstRect->xRight - m_RootShift.x, dstY2,
1162 GL_COLOR_BUFFER_BIT, GL_LINEAR);
1163 }
1164 }
1165 else
1166 {
1167 Assert(0);
1168 DEBUG_MSG_1(("BlitStretched: CrVrScrCompositorEntryRegionsGet failed rc %d\n", rc));
1169 }
1170 }
1171#endif
1172 /*
1173 glFinish();
1174 */
1175 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1176 [m_pSharedGLCtx flushBuffer];
1177}
1178
1179- (void)performSelectorMakingCurrent:(NSOpenGLContext*)pCtx idSel:(SEL)selector
1180{
1181 NSOpenGLContext *pOldCtx = vboxCtxGetCurrent();
1182 NSView *pOldView = (pOldCtx ? [pOldCtx view] : nil);
1183 NSView *pView = [pCtx view];
1184 bool fNeedCtxSwitch = (pOldCtx != pCtx || pOldView != pView);
1185 Assert(pCtx);
1186 // Assert(pOldCtx == m_pGLCtx);
1187 // Assert(pOldView == self);
1188 // Assert(fNeedCtxSwitch);
1189 if (fNeedCtxSwitch)
1190 {
1191 if(pOldCtx != nil)
1192 glFlush();
1193
1194 [pCtx makeCurrentContext];
1195 }
1196
1197 [self performSelector:selector];
1198
1199 if (fNeedCtxSwitch)
1200 {
1201 glFlush();
1202 if (pOldCtx != nil)
1203 {
1204 if ([pOldCtx view] != pOldView)
1205 {
1206 [pOldCtx setView: pOldView];
1207 }
1208
1209 [pOldCtx makeCurrentContext];
1210
1211#ifdef DEBUG
1212 {
1213 NSOpenGLContext *pTstOldCtx = [NSOpenGLContext currentContext];
1214 NSView *pTstOldView = (pTstOldCtx ? [pTstOldCtx view] : nil);
1215 Assert(pTstOldCtx == pOldCtx);
1216 Assert(pTstOldView == pOldView);
1217 }
1218#endif
1219 }
1220 else
1221 {
1222 [NSOpenGLContext clearCurrentContext];
1223 }
1224 }
1225}
1226
1227- (void)presentComposition:(PVBOXVR_SCR_COMPOSITOR)pCompositor withChangedEntry:(PVBOXVR_SCR_COMPOSITOR_ENTRY)pChangedEntry
1228{
1229 [self vboxTryDraw];
1230}
1231
1232- (void)vboxPresentToDockTileCS
1233{
1234 NSRect r = [self frame];
1235 NSRect rr = NSZeroRect;
1236 GLint i = 0;
1237 NSDockTile *pDT = nil;
1238
1239 if ([m_DockTileView thumbBitmap] != nil)
1240 {
1241 /* Only update after at least 200 ms, cause glReadPixels is
1242 * heavy performance wise. */
1243 uint64_t uiNewTime = RTTimeMilliTS();
1244 VBOXVR_SCR_COMPOSITOR_ITERATOR CIter;
1245 PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry;
1246
1247 if (uiNewTime - m_uiDockUpdateTime > 200)
1248 {
1249 m_uiDockUpdateTime = uiNewTime;
1250#if 0
1251 /* todo: check this for optimization */
1252 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, myTextureName);
1253 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_STORAGE_HINT_APPLE,
1254 GL_STORAGE_SHARED_APPLE);
1255 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1256 glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA,
1257 sizex, sizey, 0, GL_BGRA,
1258 GL_UNSIGNED_INT_8_8_8_8_REV, myImagePtr);
1259 glCopyTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB,
1260 0, 0, 0, 0, 0, image_width, image_height);
1261 glFlush();
1262 /* Do other work processing here, using a double or triple buffer */
1263 glGetTexImage(GL_TEXTURE_RECTANGLE_ARB, 0, GL_BGRA,
1264 GL_UNSIGNED_INT_8_8_8_8_REV, pixels);
1265#endif
1266 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
1267 glDrawBuffer(GL_BACK);
1268
1269 /* Clear background to transparent */
1270 glClear(GL_COLOR_BUFFER_BIT);
1271
1272 rr = [m_DockTileView frame];
1273
1274 CrVrScrCompositorIterInit(m_pCompositor, &CIter);
1275 while ((pEntry = CrVrScrCompositorIterNext(&CIter)) != NULL)
1276 {
1277 uint32_t cRegions;
1278 const RTRECT *paSrcRegions, *paDstRegions;
1279 int rc = CrVrScrCompositorEntryRegionsGet(m_pCompositor, pEntry, &cRegions, &paSrcRegions, &paDstRegions);
1280 if (RT_SUCCESS(rc))
1281 {
1282 uint32_t i;
1283
1284 glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_FBOId);
1285 glFramebufferTexture2DEXT(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, pEntry->Tex.target, pEntry->Tex.hwid, 0);
1286 glReadBuffer(GL_COLOR_ATTACHMENT0);
1287
1288 for (i = 0; i < cRegions; ++i)
1289 {
1290 const RTRECT * pSrcRect = &paSrcRegions[i];
1291 const RTRECT * pDstRect = &paDstRegions[i];
1292 GLint srcY1 = r.size.height - pSrcRect->yTop;
1293 GLint srcY2 = r.size.height - pSrcRect->yBottom;
1294 GLint dstY1 = r.size.height - pDstRect->yTop;
1295 GLint dstY2 = r.size.height - pDstRect->yBottom;
1296
1297
1298 glBlitFramebufferEXT(pSrcRect->xLeft, srcY1 + m_RootShift.y,
1299 pSrcRect->xRight, srcY2 + m_RootShift.y,
1300 pDstRect->xLeft * m_FBOThumbScaleX, dstY1 * m_FBOThumbScaleY,
1301 pDstRect->xRight * m_FBOThumbScaleX, dstY2 * m_FBOThumbScaleY,
1302 GL_COLOR_BUFFER_BIT, GL_LINEAR);
1303 }
1304 }
1305 else
1306 {
1307 Assert(0);
1308 DEBUG_MSG_1(("BlitStretched: CrVrScrCompositorEntryRegionsGet failed rc %d\n", rc));
1309 }
1310 }
1311
1312 glFinish();
1313
1314 glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
1315 glReadBuffer(GL_BACK);
1316 /* Here the magic of reading the FBO content in our own buffer
1317 * happens. We have to lock this access, in the case the dock
1318 * is updated currently. */
1319 [m_DockTileView lock];
1320 glReadPixels(0, 0, rr.size.width, rr.size.height,
1321 GL_BGRA,
1322 GL_UNSIGNED_INT_8_8_8_8,
1323 [[m_DockTileView thumbBitmap] bitmapData]);
1324 [m_DockTileView unlock];
1325
1326 pDT = [[NSApplication sharedApplication] dockTile];
1327
1328 /* Send a display message to the dock tile in the main thread */
1329 [[[NSApplication sharedApplication] dockTile] performSelectorOnMainThread:@selector(display) withObject:nil waitUntilDone:NO];
1330 }
1331 }
1332}
1333
1334- (void)clearVisibleRegions
1335{
1336 if(m_paClipRects)
1337 {
1338 RTMemFree(m_paClipRects);
1339 m_paClipRects = NULL;
1340 }
1341 m_cClipRects = 0;
1342}
1343
1344- (void)setVisibleRegions:(GLint)cRects paRects:(GLint*)paRects
1345{
1346 GLint cOldRects = m_cClipRects;
1347
1348 DEBUG_MSG_1(("OVIW(%p): setVisibleRegions: cRects=%d\n", (void*)self, cRects));
1349
1350 [self clearVisibleRegions];
1351
1352 if (cRects > 0)
1353 {
1354#ifdef DEBUG_poetzsch
1355 int i =0;
1356 for (i = 0; i < cRects; ++i)
1357 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]));
1358#endif
1359
1360 m_paClipRects = (GLint*)RTMemAlloc(sizeof(GLint) * 4 * cRects);
1361 m_cClipRects = cRects;
1362 memcpy(m_paClipRects, paRects, sizeof(GLint) * 4 * cRects);
1363 }
1364
1365 [self vboxTryDraw];
1366}
1367
1368- (NSView*)dockTileScreen
1369{
1370 NSView *contentView = [[[NSApplication sharedApplication] dockTile] contentView];
1371 NSView *screenContent = nil;
1372 /* First try the new variant which checks if this window is within the
1373 screen which is previewed in the dock. */
1374 if ([contentView respondsToSelector:@selector(screenContentWithParentView:)])
1375 screenContent = [contentView performSelector:@selector(screenContentWithParentView:) withObject:(id)m_pParentView];
1376 /* If it fails, fall back to the old variant (VBox...) */
1377 else if ([contentView respondsToSelector:@selector(screenContent)])
1378 screenContent = [contentView performSelector:@selector(screenContent)];
1379 return screenContent;
1380}
1381
1382- (void)reshapeDockTile
1383{
1384 NSRect newFrame = NSZeroRect;
1385
1386 NSView *pView = [self dockTileScreen];
1387 if (pView != nil)
1388 {
1389 NSRect dockFrame = [pView frame];
1390 NSRect parentFrame = [m_pParentView frame];
1391
1392 m_FBOThumbScaleX = (float)dockFrame.size.width / parentFrame.size.width;
1393 m_FBOThumbScaleY = (float)dockFrame.size.height / parentFrame.size.height;
1394 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));
1395 /*
1396 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));
1397 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));
1398 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);
1399 */
1400 [m_DockTileView setFrame: newFrame];
1401 }
1402}
1403
1404@end
1405
1406/********************************************************************************
1407*
1408* OpenGL context management
1409*
1410********************************************************************************/
1411void cocoaGLCtxCreate(NativeNSOpenGLContextRef *ppCtx, GLbitfield fVisParams, NativeNSOpenGLContextRef pSharedCtx)
1412{
1413 NSOpenGLPixelFormat *pFmt = nil;
1414
1415 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1416
1417 NSOpenGLPixelFormatAttribute attribs[24] =
1418 {
1419 NSOpenGLPFAWindow,
1420 NSOpenGLPFAAccelerated,
1421 NSOpenGLPFAColorSize, (NSOpenGLPixelFormatAttribute)24
1422 };
1423
1424 int i = 4;
1425
1426 if (fVisParams & CR_ALPHA_BIT)
1427 {
1428 DEBUG_MSG(("CR_ALPHA_BIT requested\n"));
1429 attribs[i++] = NSOpenGLPFAAlphaSize;
1430 attribs[i++] = 8;
1431 }
1432 if (fVisParams & CR_DEPTH_BIT)
1433 {
1434 DEBUG_MSG(("CR_DEPTH_BIT requested\n"));
1435 attribs[i++] = NSOpenGLPFADepthSize;
1436 attribs[i++] = 24;
1437 }
1438 if (fVisParams & CR_STENCIL_BIT)
1439 {
1440 DEBUG_MSG(("CR_STENCIL_BIT requested\n"));
1441 attribs[i++] = NSOpenGLPFAStencilSize;
1442 attribs[i++] = 8;
1443 }
1444 if (fVisParams & CR_ACCUM_BIT)
1445 {
1446 DEBUG_MSG(("CR_ACCUM_BIT requested\n"));
1447 attribs[i++] = NSOpenGLPFAAccumSize;
1448 if (fVisParams & CR_ALPHA_BIT)
1449 attribs[i++] = 32;
1450 else
1451 attribs[i++] = 24;
1452 }
1453 if (fVisParams & CR_MULTISAMPLE_BIT)
1454 {
1455 DEBUG_MSG(("CR_MULTISAMPLE_BIT requested\n"));
1456 attribs[i++] = NSOpenGLPFASampleBuffers;
1457 attribs[i++] = 1;
1458 attribs[i++] = NSOpenGLPFASamples;
1459 attribs[i++] = 4;
1460 }
1461 if (fVisParams & CR_DOUBLE_BIT)
1462 {
1463 DEBUG_MSG(("CR_DOUBLE_BIT requested\n"));
1464 attribs[i++] = NSOpenGLPFADoubleBuffer;
1465 }
1466 if (fVisParams & CR_STEREO_BIT)
1467 {
1468 /* We don't support that.
1469 DEBUG_MSG(("CR_STEREO_BIT requested\n"));
1470 attribs[i++] = NSOpenGLPFAStereo;
1471 */
1472 }
1473
1474 /* Mark the end */
1475 attribs[i++] = 0;
1476
1477 /* Choose a pixel format */
1478 pFmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
1479
1480 if (pFmt)
1481 {
1482 *ppCtx = [[OverlayOpenGLContext alloc] initWithFormat:pFmt shareContext:pSharedCtx];
1483
1484 /* Enable multi threaded OpenGL engine */
1485 /*
1486 CGLContextObj cglCtx = [*ppCtx CGLContextObj];
1487 CGLError err = CGLEnable(cglCtx, kCGLCEMPEngine);
1488 if (err != kCGLNoError)
1489 printf ("Couldn't enable MT OpenGL engine!\n");
1490 */
1491
1492 DEBUG_MSG(("New context %X\n", (uint)*ppCtx));
1493 }
1494
1495 [pPool release];
1496}
1497
1498void cocoaGLCtxDestroy(NativeNSOpenGLContextRef pCtx)
1499{
1500 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1501
1502 /*
1503 [pCtx release];
1504 */
1505
1506 [pPool release];
1507}
1508
1509/********************************************************************************
1510*
1511* View management
1512*
1513********************************************************************************/
1514void cocoaViewCreate(NativeNSViewRef *ppView, WindowInfo *pWinInfo, NativeNSViewRef pParentView, GLbitfield fVisParams)
1515{
1516 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1517
1518 /* Create our worker view */
1519 OverlayView* pView = [[OverlayView alloc] initWithFrame:NSZeroRect thread:RTThreadSelf() parentView:pParentView winInfo:pWinInfo];
1520
1521 if (pView)
1522 {
1523 /* We need a real window as container for the view */
1524 [[OverlayWindow alloc] initWithParentView:pParentView overlayView:pView];
1525 /* Return the freshly created overlay view */
1526 *ppView = pView;
1527 }
1528
1529 [pPool release];
1530}
1531
1532void cocoaViewReparent(NativeNSViewRef pView, NativeNSViewRef pParentView)
1533{
1534 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1535
1536 OverlayView* pOView = (OverlayView*)pView;
1537
1538 if (pOView)
1539 {
1540 /* Make sure the window is removed from any previous parent window. */
1541 if ([[pOView overlayWin] parentWindow] != nil)
1542 {
1543 [[[pOView overlayWin] parentWindow] removeChildWindow:[pOView overlayWin]];
1544 }
1545
1546 /* Set the new parent view */
1547 [pOView setParentView: pParentView];
1548
1549 /* Add the overlay window as a child to the new parent window */
1550 if (pParentView != nil)
1551 {
1552 [[pParentView window] addChildWindow:[pOView overlayWin] ordered:NSWindowAbove];
1553 [pOView createDockTile];
1554 }
1555 }
1556
1557 [pPool release];
1558}
1559
1560void cocoaViewDestroy(NativeNSViewRef pView)
1561{
1562 NSWindow *pWin = nil;
1563
1564 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1565
1566 /* Hide the view early */
1567 [pView setHidden: YES];
1568
1569 pWin = [pView window];
1570 [[NSNotificationCenter defaultCenter] removeObserver:pWin];
1571 [pWin setContentView: nil];
1572 [[pWin parentWindow] removeChildWindow: pWin];
1573
1574 /*
1575 a = [pWin retainCount];
1576 for (; a > 1; --a)
1577 [pWin performSelector:@selector(release)]
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 which should cause no harm */
1583 [pWin performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO];
1584 /*
1585 [pWin release];
1586 */
1587
1588 /* We can NOT run synchronously with the main thread since this may lead to a deadlock,
1589 caused by main thread waiting xpcom thread, xpcom thread waiting to main hgcm thread,
1590 and main hgcm thread waiting for us, this is why use waitUntilDone:NO.
1591 We need to avoid concurrency though, so we cleanup some data right away via a cleanupData call */
1592 [(OverlayView*)pView cleanupData];
1593
1594 /* There seems to be a bug in the performSelector method which is called in
1595 * parentWindowChanged above. The object is retained but not released. This
1596 * results in an unbalanced reference count, which is here manually
1597 * decremented. */
1598 /*
1599 a = [pView retainCount];
1600 for (; a > 1; --a)
1601 */
1602 [pView performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO];
1603 /*
1604 [pView release];
1605 */
1606
1607 [pPool release];
1608}
1609
1610void cocoaViewShow(NativeNSViewRef pView, GLboolean fShowIt)
1611{
1612 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1613
1614 [pView setHidden: fShowIt==GL_TRUE?NO:YES];
1615
1616 [pPool release];
1617}
1618
1619void cocoaViewDisplay(NativeNSViewRef pView)
1620{
1621 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1622
1623 DEBUG_MSG_1(("cocoaViewDisplay %p\n", (void*)pView));
1624 [(OverlayView*)pView swapFBO];
1625
1626 [pPool release];
1627
1628}
1629
1630void cocoaViewSetPosition(NativeNSViewRef pView, NativeNSViewRef pParentView, int x, int y)
1631{
1632 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1633
1634 [(OverlayView*)pView setPos:NSMakePoint(x, y)];
1635
1636 [pPool release];
1637}
1638
1639void cocoaViewSetSize(NativeNSViewRef pView, int w, int h)
1640{
1641 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1642
1643 [(OverlayView*)pView setSize:NSMakeSize(w, h)];
1644
1645 [pPool release];
1646}
1647
1648void cocoaViewGetGeometry(NativeNSViewRef pView, int *pX, int *pY, int *pW, int *pH)
1649{
1650 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1651
1652 NSRect frame = [[pView window] frame];
1653 *pX = frame.origin.x;
1654 *pY = frame.origin.y;
1655 *pW = frame.size.width;
1656 *pH = frame.size.height;
1657
1658 [pPool release];
1659}
1660
1661void cocoaViewPresentComposition(NativeNSViewRef pView, struct VBOXVR_SCR_COMPOSITOR * pCompositor, struct VBOXVR_SCR_COMPOSITOR_ENTRY *pChangedEntry)
1662{
1663 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1664
1665 [(OverlayView*)pView presentComposition:pCompositor withChangedEntry:pChangedEntry];
1666
1667 [pPool release];
1668}
1669
1670void cocoaViewMakeCurrentContext(NativeNSViewRef pView, NativeNSOpenGLContextRef pCtx)
1671{
1672 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1673
1674 DEBUG_MSG(("cocoaViewMakeCurrentContext(%p, %p)\n", (void*)pView, (void*)pCtx));
1675
1676 if (pView)
1677 {
1678 [(OverlayView*)pView setGLCtx:pCtx];
1679 [(OverlayView*)pView makeCurrentFBO];
1680 }
1681 else
1682 {
1683 [NSOpenGLContext clearCurrentContext];
1684 }
1685
1686 [pPool release];
1687}
1688
1689void cocoaViewSetVisibleRegion(NativeNSViewRef pView, GLint cRects, GLint* paRects)
1690{
1691 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1692
1693 [(OverlayView*)pView setVisibleRegions:cRects paRects:paRects];
1694
1695 [pPool release];
1696}
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