VirtualBox

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

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

HostServices/OpenGL: compile fix for certin environments

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