VirtualBox

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

Last change on this file since 50095 was 50095, checked in by vboxsync, 11 years ago

crOpenGL: presentation infrastructure rework (still work in progress)

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette