VirtualBox

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

Last change on this file since 53594 was 53594, checked in by vboxsync, 10 years ago

Mac OS X host: 3D: kCGLPFAWindow and NSOpenGLPFAWindow were deprecated, remove them from pixel format attrubites list (some Mac hosts might refuse 3D initialization if attributes present).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 78.7 KB
Line 
1/* $Id: renderspu_cocoa_helper.m 53594 2014-12-21 19:18:04Z vboxsync $ */
2/** @file
3 * VirtualBox OpenGL Cocoa Window System Helper Implementation.
4 */
5
6/*
7 * Copyright (C) 2009-2014 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/** @page pg_opengl_cocoa OpenGL - Cocoa Window System Helper
19 *
20 * How this works:
21 * In general it is not so easy like on the other platforms, cause Cocoa
22 * doesn't support any clipping of already painted stuff. In Mac OS X there is
23 * the concept of translucent canvas's e.g. windows and there it is just
24 * painted what should be visible to the user. Unfortunately this isn't the
25 * concept of chromium. Therefor I reroute all OpenGL operation from the guest
26 * to a frame buffer object (FBO). This is a OpenGL extension, which is
27 * supported by all OS X versions we support (AFAIC tell). Of course the guest
28 * doesn't know that and we have to make sure that the OpenGL state always is
29 * in the right state to paint into the FBO and not to the front/back buffer.
30 * Several functions below (like cocoaBindFramebufferEXT, cocoaGetIntegerv,
31 * ...) doing this. When a swap or finish is triggered by the guest, the
32 * content (which is already bound to an texture) is painted on the screen
33 * within a separate OpenGL context. This allows the usage of the same
34 * resources (texture ids, buffers ...) but at the same time having an
35 * different internal OpenGL state. Another advantage is that we can paint a
36 * thumbnail of the current output in a much more smaller (GPU accelerated
37 * scale) version on a third context and use glReadPixels to get the actual
38 * data. glReadPixels is a very slow operation, but as we just use a much more
39 * smaller image, we can handle it (anyway this is only done 5 times per
40 * second).
41 *
42 * Other things to know:
43 * - If the guest request double buffering, we have to make sure there are two
44 * buffers. We use the same FBO with 2 color attachments. Also glDrawBuffer
45 * and glReadBuffer is intercepted to make sure it is painted/read to/from
46 * the correct buffers. On swap our buffers are swapped and not the
47 * front/back buffer.
48 * - If the guest request a depth/stencil buffer, a combined render buffer for
49 * this is created.
50 * - If the size of the guest OpenGL window changes, all FBO's, textures, ...
51 * need to be recreated.
52 * - We need to track any changes to the parent window
53 * (create/destroy/move/resize). The various classes like OverlayHelperView,
54 * OverlayWindow, ... are there for.
55 * - The HGCM service runs on a other thread than the Main GUI. Keeps this
56 * always in mind (see e.g. performSelectorOnMainThread in renderFBOToView)
57 * - We make heavy use of late binding. We can not be sure that the GUI (or any
58 * other third party GUI), overwrite our NSOpenGLContext. So we always ask if
59 * this is our own one, before use. Really neat concept of Objective-C/Cocoa
60 * ;)
61 */
62
63/*******************************************************************************
64* Header Files *
65*******************************************************************************/
66#include "renderspu_cocoa_helper.h"
67
68#import <Cocoa/Cocoa.h>
69#undef PVM /* sys/param.h (included via Cocoa.h) pollutes the namespace with this define. */
70
71#include "chromium.h" /* For the visual bits of chromium */
72
73#include <iprt/thread.h>
74#include <iprt/string.h>
75#include <iprt/mem.h>
76#include <iprt/time.h>
77#include <iprt/assert.h>
78#include <VBox/VBoxOGLTest.h>
79
80#include <cr_vreg.h>
81#include <cr_error.h>
82#include <cr_blitter.h>
83#ifdef VBOX_WITH_CRDUMPER_THUMBNAIL
84# include <cr_pixeldata.h>
85#endif
86
87
88#include "renderspu.h"
89
90
91/*******************************************************************************
92* Defined Constants And Macros *
93*******************************************************************************/
94/* Debug macros */
95/** @def FBO
96 * Disable this to see how the output is without the FBO in the middle of the processing chain. */
97#define FBO 1
98/** @def CR_RENDER_FORCE_PRESENT_MAIN_THREAD
99 * Force present schedule to main thread. */
100/** @def SHOW_WINDOW_BACKGROUND
101 * Define this to see the window background even if the window is clipped. */
102/** @def DEBUG_VERBOSE
103 * Define this to get some debug info about the messages flow. */
104#if 0 || defined(DOXYGEN_RUNNING)
105# define CR_RENDER_FORCE_PRESENT_MAIN_THREAD
106# define SHOW_WINDOW_BACKGROUND 1
107# define DEBUG_VERBOSE
108#endif
109
110#ifdef DEBUG_VERBOSE
111# error "should be disabled!"
112# define DEBUG_INFO(text) do { \
113 crWarning text ; \
114 AssertFailed(); \
115 } while (0)
116
117# define DEBUG_WARN(text) do { \
118 crWarning text ; \
119 AssertFailed(); \
120 } while (0)
121
122# define DEBUG_MSG(text) do { printf text; } while (0)
123# define DEBUG_MSG_1(text) do { printf text; } while (0)
124
125#else
126
127# define DEBUG_INFO(text) do { \
128 crInfo text ; \
129 } while (0)
130
131# define DEBUG_WARN(text) do { \
132 crWarning text ; \
133 } while (0)
134
135# define DEBUG_MSG(text) do {} while (0)
136# define DEBUG_MSG_1(text) do {} while (0)
137
138#endif
139
140
141#define DEBUG_FUNC_ENTER() DEBUG_MSG(("==>%s\n", __PRETTY_FUNCTION__))
142#define DEBUG_FUNC_LEAVE() DEBUG_MSG(("<==%s\n", __PRETTY_FUNCTION__))
143
144#define DEBUG_GL_SAVE_STATE() \
145 do { \
146 glPushAttrib(GL_ALL_ATTRIB_BITS); \
147 glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS); \
148 glMatrixMode(GL_PROJECTION); \
149 glPushMatrix(); \
150 glMatrixMode(GL_TEXTURE); \
151 glPushMatrix(); \
152 glMatrixMode(GL_COLOR); \
153 glPushMatrix(); \
154 glMatrixMode(GL_MODELVIEW); \
155 glPushMatrix(); \
156 } while (0)
157
158#define DEBUG_GL_RESTORE_STATE() \
159 do { \
160 glMatrixMode(GL_MODELVIEW); \
161 glPopMatrix(); \
162 glMatrixMode(GL_COLOR); \
163 glPopMatrix(); \
164 glMatrixMode(GL_TEXTURE); \
165 glPopMatrix(); \
166 glMatrixMode(GL_PROJECTION); \
167 glPopMatrix(); \
168 glPopClientAttrib(); \
169 glPopAttrib(); \
170 } while (0)
171
172#ifdef DEBUG_poetzsch
173# define DEBUG_CHECK_GL_ERROR() do { checkGLError(__FILE__, __LINE__); } while (0);
174static void checkGLError(char *pszFile, int iLine)
175{
176 GLenum uGlErr = glGetError();
177 if (uGlErr != GL_NO_ERROR)
178 {
179 const char *errStr;
180 switch (uGlErr)
181 {
182 case GL_INVALID_ENUM: errStr = "GL_INVALID_ENUM"; break;
183 case GL_INVALID_VALUE: errStr = "GL_INVALID_VALUE"; break;
184 case GL_INVALID_OPERATION: errStr = "GL_INVALID_OPERATION"; break;
185 case GL_STACK_OVERFLOW: errStr = "GL_STACK_OVERFLOW"; break;
186 case GL_STACK_UNDERFLOW: errStr = "GL_STACK_UNDERFLOW"; break;
187 case GL_OUT_OF_MEMORY: errStr = "GL_OUT_OF_MEMORY"; break;
188 case GL_TABLE_TOO_LARGE: errStr = "GL_TABLE_TOO_LARGE"; break;
189 default: errStr = "UNKNOWN"; break;
190 }
191 DEBUG_MSG(("%s:%d: glError %d (%s)\n", pszFile, iLine, uGlErr, errStr));
192 }
193}
194#else
195# define DEBUG_CHECK_GL_ERROR() do {} while (0)
196#endif
197
198
199
200static NSOpenGLContext *vboxCtxGetCurrent(void)
201{
202 GET_CONTEXT(pCtxInfo);
203 if (pCtxInfo)
204 {
205 Assert(pCtxInfo->context);
206 return pCtxInfo->context;
207 }
208
209 return nil;
210}
211
212static bool vboxCtxSyncCurrentInfo(void)
213{
214 GET_CONTEXT(pCtxInfo);
215 NSOpenGLContext *pCtx = [NSOpenGLContext currentContext];
216 NSView *pView = pCtx ? [pCtx view] : nil;
217 bool fAdjusted = false;
218 if (pCtxInfo)
219 {
220 WindowInfo *pWinInfo = pCtxInfo->currentWindow;
221 Assert(pWinInfo);
222 if ( pCtxInfo->context != pCtx
223 || pWinInfo->window != pView)
224 {
225 renderspu_SystemMakeCurrent(pWinInfo, 0, pCtxInfo);
226 fAdjusted = true;
227 }
228 }
229 else if (pCtx)
230 {
231 [NSOpenGLContext clearCurrentContext];
232 fAdjusted = true;
233 }
234
235 return fAdjusted;
236}
237
238
239/**
240 * State carrying structure for use with vboxCtxEnter and vboxCtxLeave
241 */
242typedef struct VBOX_CR_RENDER_CTX_INFO
243{
244 bool fIsValid;
245 NSOpenGLContext *pCtx;
246 NSView *pView;
247} VBOX_CR_RENDER_CTX_INFO;
248/** Pointer to render context info for use with vboxCtxEnter/Leave. */
249typedef VBOX_CR_RENDER_CTX_INFO *PVBOX_CR_RENDER_CTX_INFO;
250
251static void vboxCtxEnter(NSOpenGLContext *pNewCtx, PVBOX_CR_RENDER_CTX_INFO pCtxInfo)
252{
253 NSOpenGLContext *pOldCtx = vboxCtxGetCurrent();
254 NSView *pOldView = pOldCtx ? [pOldCtx view] : nil;
255 NSView *pNewView = [pNewCtx view];
256
257 Assert(pNewCtx);
258
259 if ( pOldCtx != pNewCtx
260 || pOldView != pNewView)
261 {
262 if (pOldCtx != nil)
263 glFlush();
264
265 [pNewCtx makeCurrentContext];
266
267 pCtxInfo->fIsValid = true;
268 pCtxInfo->pCtx = pOldCtx;
269 /** @todo r=bird: Why do we save the NEW VIEW here? vboxCtxLeave calls it 'pOldView'. Bug? */
270 pCtxInfo->pView = pNewView;
271 }
272 else
273 {
274 /* No context switch necessary. */
275 pCtxInfo->fIsValid = false;
276 }
277}
278
279static void vboxCtxLeave(PVBOX_CR_RENDER_CTX_INFO pCtxInfo)
280{
281 if (pCtxInfo->fIsValid)
282 {
283 NSOpenGLContext *pOldCtx = pCtxInfo->pCtx;
284 NSView *pOldView = pCtxInfo->pView;
285
286 glFlush();
287 if (pOldCtx != nil)
288 {
289 /* vboxCtxEnter saves the new view, not the old. So, what we actually
290 do here is switching the view of the old context to that of the new
291 one (wrt vboxCtxEnter) before making it current. */
292 /** @todo r=bird: Figure out what we really want to do here, and either rename
293 * pOldView or fix the code. */
294 if ([pOldCtx view] != pOldView)
295 {
296 [pOldCtx setView: pOldView];
297 }
298
299 [pOldCtx makeCurrentContext];
300
301#ifdef VBOX_STRICT
302 {
303 NSOpenGLContext *pTstOldCtx = [NSOpenGLContext currentContext];
304 NSView *pTstOldView = pTstOldCtx ? [pTstOldCtx view] : nil;
305 Assert(pTstOldCtx == pOldCtx);
306 Assert(pTstOldView == pOldView);
307 }
308#endif
309 }
310 else
311 {
312 [NSOpenGLContext clearCurrentContext];
313 }
314 }
315}
316
317
318/**
319 * Custom OpenGL context class.
320 *
321 * This implementation doesn't allow to set a view to the context, but save the
322 * view for later use. Also it saves a copy of the pixel format used to create
323 * that context for later use.
324 */
325@interface OverlayOpenGLContext: NSOpenGLContext
326{
327@private
328 NSOpenGLPixelFormat *m_pPixelFormat;
329 NSView *m_pView;
330}
331- (NSOpenGLPixelFormat *)openGLPixelFormat;
332@end
333
334/**
335 * Abstrack task class.
336 */
337@interface VBoxTask : NSObject
338{
339}
340- (void)run;
341@end
342
343@implementation VBoxTask
344/** Run method that the child classes must reimplement.
345 * This will abort the process. */
346- (void)run
347{
348 AssertReleaseFailed();
349}
350@end
351
352
353/**
354 * Generic task class for executing a given method select.
355 */
356@interface VBoxTaskPerformSelector : VBoxTask
357{
358@private
359 id m_Object;
360 SEL m_Selector;
361 id m_Arg;
362}
363- (id)initWithObject:(id)aObject selector:(SEL)aSelector arg:(id)aArg;
364- (void)run;
365- (void)dealloc;
366@end
367
368@implementation VBoxTaskPerformSelector
369
370/**
371 * Initializes a VBoxTaskPerformSelector.
372 *
373 * @param aObject The object (reference not consumed).
374 * @param aSelector The method selector.
375 * @param aArg The method argument (reference not consumed).
376 */
377- (id)initWithObject:(id)aObject selector:(SEL)aSelector arg:(id)aArg
378{
379 self = [super init];
380 if (self)
381 {
382 [aObject retain];
383 m_Object = aObject;
384 m_Selector = aSelector;
385 if (aArg != nil)
386 [aArg retain];
387 m_Arg = aArg;
388 }
389
390 return self;
391}
392
393- (void)run
394{
395 [m_Object performSelector:m_Selector withObject:m_Arg];
396}
397
398- (void)dealloc
399{
400 [m_Object release];
401 if (m_Arg != nil)
402 [m_Arg release];
403
404 [super dealloc];
405}
406@end
407
408
409/**
410 *
411 */
412@interface VBoxTaskComposite : VBoxTask
413{
414@private
415 NSUInteger m_CurIndex;
416 RTCRITSECT m_Lock;
417 NSMutableArray *m_pArray;
418}
419- (id)init;
420- (void)add:(VBoxTask *)pTask;
421- (void)run;
422- (void)dealloc;
423@end
424
425@implementation VBoxTaskComposite
426- (id)init
427{
428 self = [super init];
429
430 if (self)
431 {
432 int rc = RTCritSectInit(&m_Lock);
433 if (!RT_SUCCESS(rc))
434 {
435 DEBUG_WARN(("RTCritSectInit failed %d\n", rc));
436 return nil;
437 }
438
439 m_CurIndex = 0;
440
441 m_pArray = [[NSMutableArray alloc] init];
442 }
443
444 return self;
445}
446
447/**
448 * Adds a task to the composite task object.
449 *
450 * @param pTask Task to add. Reference is NOT consumed.
451 */
452- (void)add:(VBoxTask *)pTask
453{
454 [pTask retain];
455 int rc = RTCritSectEnter(&m_Lock);
456 if (RT_SUCCESS(rc))
457 {
458 [m_pArray addObject:pTask];
459 RTCritSectLeave(&m_Lock);
460 }
461 else
462 {
463 DEBUG_WARN(("RTCritSectEnter failed %d\n", rc));
464 [pTask release];
465 }
466}
467
468- (void)run
469{
470 for (;;)
471 {
472 /*
473 * Dequeue a task.
474 */
475 int rc = RTCritSectEnter(&m_Lock);
476 if (RT_FAILURE(rc))
477 {
478 DEBUG_WARN(("RTCritSectEnter failed %d\n", rc));
479 break;
480 }
481
482 NSUInteger count = [m_pArray count];
483 Assert(m_CurIndex <= count);
484 if (m_CurIndex == count)
485 {
486 [m_pArray removeAllObjects];
487 m_CurIndex = 0;
488 RTCritSectLeave(&m_Lock);
489 break;
490 }
491
492 VBoxTask *pTask = (VBoxTask *)[m_pArray objectAtIndex:m_CurIndex];
493 Assert(pTask != nil);
494
495 ++m_CurIndex;
496
497 /*
498 * Remove the first 1025 empty entires.
499 */
500 if (m_CurIndex > 1024)
501 {
502 NSRange range;
503 range.location = 0;
504 range.length = m_CurIndex;
505 [m_pArray removeObjectsInRange:range];
506 m_CurIndex = 0;
507 }
508 RTCritSectLeave(&m_Lock);
509
510 /*
511 * Run the task and release it.
512 */
513 [pTask run];
514 [pTask release];
515 }
516}
517
518- (void)dealloc
519{
520 NSUInteger count = [m_pArray count];
521 for (;m_CurIndex < count; ++m_CurIndex)
522 {
523 VBoxTask *pTask = (VBoxTask*)[m_pArray objectAtIndex:m_CurIndex];
524 DEBUG_WARN(("dealloc with non-empty tasks! %p\n", pTask));
525 [pTask release];
526 }
527
528 [m_pArray release];
529 RTCritSectDelete(&m_Lock);
530
531 [super dealloc];
532}
533@end
534
535
536/**
537 *
538 *
539 */
540@interface VBoxMainThreadTaskRunner : NSObject
541{
542@private
543 VBoxTaskComposite *m_pTasks;
544}
545- (id)init;
546- (void)add:(VBoxTask *)pTask;
547- (void)addObj:(id)aObject selector:(SEL)aSelector arg:(id)aArg;
548- (void)runTasks;
549- (bool)runTasksSyncIfPossible;
550- (void)dealloc;
551+ (VBoxMainThreadTaskRunner *) globalInstance;
552@end
553
554@implementation VBoxMainThreadTaskRunner
555- (id)init
556{
557 self = [super init];
558 if (self)
559 {
560 m_pTasks = [[VBoxTaskComposite alloc] init];
561 }
562
563 return self;
564}
565
566+ (VBoxMainThreadTaskRunner *) globalInstance
567{
568 static dispatch_once_t s_DispatchOnce;
569 static VBoxMainThreadTaskRunner *s_pRunner = nil;
570 dispatch_once(&s_DispatchOnce, ^{
571 s_pRunner = [[VBoxMainThreadTaskRunner alloc] init];
572 });
573 return s_pRunner;
574}
575
576- (void)add:(VBoxTask *)pTask
577{
578 DEBUG_FUNC_ENTER();
579 [m_pTasks add:pTask];
580 /** @todo r=bird: Unbalanced [self retain]. */
581 [self retain];
582
583 if (![self runTasksSyncIfPossible])
584 {
585 DEBUG_MSG(("task will be processed async\n"));
586 [self performSelectorOnMainThread:@selector(runTasks) withObject:nil waitUntilDone:NO];
587 }
588
589 DEBUG_FUNC_LEAVE();
590}
591
592/**
593 * Adds a task calling an object method (selector).
594 *
595 * @param aObject The object (reference not consumed)..
596 * @param aSelector The method selector.
597 * @param aArg The method argument (reference not consumed).
598 */
599- (void)addObj:(id)aObject selector:(SEL)aSelector arg:(id)aArg
600{
601 VBoxTaskPerformSelector *pSelTask = [[VBoxTaskPerformSelector alloc] initWithObject:aObject selector:aSelector arg:aArg];
602 [self add:pSelTask];
603 [pSelTask release];
604}
605
606
607/**
608 * Internal method for running the pending tasks.
609 */
610- (void)runTasks
611{
612 if ([NSThread isMainThread])
613 {
614 [m_pTasks run];
615 /** @todo r=bird: This release and the retain in the add method aren't
616 * necessarily balanced if there are more than one call to add().
617 *
618 * This could probably end up deleting the singleton prematurely and leave
619 * globalInstance() returning pointers to a stale object in freed memory,
620 * quite possibly causing crashes or/and heap corruption. */
621 [self release];
622 }
623 else
624 {
625 DEBUG_WARN(("run tasks called not on main thread!\n"));
626#ifndef DEBUG_VERBOSE
627 AssertFailed();
628#endif
629 [self performSelectorOnMainThread:@selector(runTasks) withObject:nil waitUntilDone:YES];
630 }
631}
632
633/**
634 * Callback for calling runTasks via renderspuCalloutClient.
635 * @param pvUser The VBoxMainThreadTaskRunner singleton.
636 */
637static DECLCALLBACK(void) VBoxMainThreadTaskRunner_RcdRunCallback(void *pvUser)
638{
639 DEBUG_FUNC_ENTER();
640 VBoxMainThreadTaskRunner *pRunner = (VBoxMainThreadTaskRunner *)pvUser;
641 Assert(pRunner == [VBoxMainThreadTaskRunner globalInstance]);
642 [pRunner runTasks];
643 DEBUG_FUNC_LEAVE();
644}
645
646/**
647 * Runs pending tasks synchronously, if possible in the current context.
648 *
649 * @returns true if executed tasks, false if not possible.
650 */
651- (bool)runTasksSyncIfPossible
652{
653 /*
654 * Call on main thread (?) via renderspuCalloutClient (whatever that is).
655 */
656 if (renderspuCalloutAvailable())
657 {
658 Assert(![NSThread isMainThread]);
659 renderspuCalloutClient(VBoxMainThreadTaskRunner_RcdRunCallback, self);
660 return true;
661 }
662
663 /*
664 * Run directly if on main thread.
665 */
666 if ([NSThread isMainThread])
667 {
668 [self runTasks];
669 return true;
670 }
671
672 /* Not possible. */
673 return false;
674}
675
676- (void)dealloc
677{
678 /** @todo r=bird: WTF is the point of the deallocator. The object is a singelton
679 * stored in an inaccessible static variable! */
680 [m_pTasks release];
681 m_pTasks = nil;
682
683 [super dealloc];
684}
685
686@end
687
688@class DockOverlayView;
689
690/**
691 * The custom view class.
692 *
693 * This is the main class of the cocoa OpenGL implementation. It manages a
694 * frame buffer object for the rendering of the guest applications. The guest
695 * applications render in this frame buffer which is bound to an OpenGL texture.
696 * To display the guest content, a secondary shared OpenGL context of the main
697 * OpenGL context is created. The secondary context is marked as non-opaque and
698 * the texture is displayed on an object which is composed out of the several
699 * visible region rectangles.
700 */
701@interface OverlayView : NSView
702{
703@private
704 NSView *m_pParentView;
705 NSWindow *m_pOverlayWin;
706
707 NSOpenGLContext *m_pGLCtx;
708 NSOpenGLContext *m_pSharedGLCtx;
709 RTTHREAD m_Thread;
710
711 GLuint m_FBOId;
712
713 /** The corresponding dock tile view of this OpenGL view & all helper
714 * members. */
715 DockOverlayView *m_DockTileView;
716
717 GLfloat m_FBOThumbScaleX;
718 GLfloat m_FBOThumbScaleY;
719 uint64_t m_msDockUpdateTS;
720
721 /** @name For clipping
722 * @{ */
723 GLint m_cClipRects;
724 GLint *m_paClipRects;
725 /** @} */
726
727 /** @name Position/Size tracking
728 * @{ */
729 NSPoint m_Pos;
730 NSSize m_Size;
731 /** @} */
732
733 /** This is necessary for clipping on the root window */
734 NSRect m_RootRect;
735 float m_yInvRootOffset;
736
737 CR_BLITTER *m_pBlitter;
738 WindowInfo *m_pWinInfo;
739 bool m_fNeedViewportUpdate;
740 bool m_fNeedCtxUpdate;
741 bool m_fDataVisible;
742 bool m_fCleanupNeeded;
743 bool m_fEverSized;
744}
745- (id)initWithFrame:(NSRect)frame thread:(RTTHREAD)aThread parentView:(NSView *)pParentView winInfo:(WindowInfo *)pWinInfo;
746- (void)setGLCtx:(NSOpenGLContext*)pCtx;
747- (NSOpenGLContext *)glCtx;
748
749- (void)setParentView: (NSView *)view;
750- (NSView *)parentView;
751- (void)setOverlayWin: (NSWindow *)win;
752- (NSWindow *)overlayWin;
753
754- (void)vboxSetPos:(NSPoint)pos;
755- (void)vboxSetPosUI:(NSPoint)pos;
756- (void)vboxSetPosUIObj:(NSValue *)pPos;
757- (NSPoint)pos;
758- (bool)isEverSized;
759- (void)vboxDestroy;
760- (void)vboxSetSizeUI:(NSSize)size;
761- (void)vboxSetSizeUIObj:(NSValue *)pSize;
762- (void)vboxSetSize:(NSSize)size;
763- (NSSize)size;
764- (void)updateViewportCS;
765- (void)vboxReshapePerform;
766- (void)vboxReshapeOnResizePerform;
767- (void)vboxReshapeOnReparentPerform;
768
769- (void)createDockTile;
770- (void)deleteDockTile;
771
772- (void)makeCurrentFBO;
773- (void)swapFBO;
774- (void)vboxSetVisible:(GLboolean)fVisible;
775- (void)vboxSetVisibleUIObj:(NSNumber *)pVisible;
776- (void)vboxSetVisibleUI:(GLboolean)fVisible;
777- (void)vboxTryDraw;
778- (void)vboxTryDrawUI;
779- (void)vboxReparent:(NSView *)pParentView;
780- (void)vboxReparentUI:(NSView *)pParentView;
781- (void)vboxPresent:(const VBOXVR_SCR_COMPOSITOR *)pCompositor;
782- (void)vboxPresentCS:(const VBOXVR_SCR_COMPOSITOR *)pCompositor;
783- (void)vboxPresentToDockTileCS:(const VBOXVR_SCR_COMPOSITOR *)pCompositor;
784- (void)vboxPresentToViewCS:(const VBOXVR_SCR_COMPOSITOR *)pCompositor;
785- (void)presentComposition:(const VBOXVR_SCR_COMPOSITOR_ENTRY *)pChangedEntry;
786- (void)vboxBlitterSyncWindow;
787
788- (void)clearVisibleRegions;
789- (void)setVisibleRegions:(GLint)cRects paRects:(const GLint *)paRects;
790- (GLboolean)vboxNeedsEmptyPresent;
791
792- (NSView *)dockTileScreen;
793- (void)reshapeDockTile;
794- (void)cleanupData;
795@end
796
797/**
798 * Helper view.
799 *
800 * This view is added as a sub view of the parent view to track
801 * main window changes. Whenever the main window is changed
802 * (which happens on fullscreen/seamless entry/exit) the overlay
803 * window is informed & can add them self as a child window
804 * again.
805 */
806@class OverlayWindow;
807@interface OverlayHelperView: NSView
808{
809@private
810 OverlayWindow *m_pOverlayWindow;
811}
812-(id)initWithOverlayWindow:(OverlayWindow *)pOverlayWindow;
813@end
814
815/**
816 * Custom window class.
817 *
818 * This is the overlay window which contains our custom NSView.
819 * Its a direct child of the Qt Main window. It marks its background
820 * transparent & non opaque to make clipping possible. It also disable mouse
821 * events and handle frame change events of the parent view.
822 */
823@interface OverlayWindow : NSWindow
824{
825@private
826 NSView *m_pParentView;
827 OverlayView *m_pOverlayView;
828 OverlayHelperView *m_pOverlayHelperView;
829 NSThread *m_Thread;
830}
831- (id)initWithParentView:(NSView *)pParentView overlayView:(OverlayView *)pOverlayView;
832- (void)parentWindowFrameChanged:(NSNotification *)note;
833- (void)parentWindowChanged:(NSWindow *)pWindow;
834@end
835
836
837/**
838 * Dock overlay view class.
839 */
840@interface DockOverlayView: NSView
841{
842 NSBitmapImageRep *m_ThumbBitmap;
843 NSImage *m_ThumbImage;
844 NSLock *m_Lock;
845}
846- (void)dealloc;
847- (void)cleanup;
848- (void)lock;
849- (void)unlock;
850- (void)setFrame:(NSRect)frame;
851- (void)drawRect:(NSRect)aRect;
852- (NSBitmapImageRep *)thumbBitmap;
853- (NSImage *)thumbImage;
854@end
855
856@implementation DockOverlayView
857- (id)init
858{
859 DEBUG_FUNC_ENTER();
860 self = [super init];
861 if (self)
862 {
863 /*
864 * We need a lock cause the thumb image could be accessed from the main
865 * thread when someone is calling display on the dock tile & from the
866 * OpenGL thread when the thumbnail is updated.
867 */
868 m_Lock = [[NSLock alloc] init];
869 }
870
871 DEBUG_FUNC_LEAVE();
872
873 return self;
874}
875
876- (void)dealloc
877{
878 DEBUG_FUNC_ENTER();
879
880 [self cleanup];
881 [m_Lock release];
882
883 [super dealloc];
884
885 DEBUG_FUNC_LEAVE();
886}
887
888- (void)cleanup
889{
890 DEBUG_FUNC_ENTER();
891
892 if (m_ThumbImage != nil)
893 {
894 [m_ThumbImage release];
895 m_ThumbImage = nil;
896 }
897
898 if (m_ThumbBitmap != nil)
899 {
900 [m_ThumbBitmap release];
901 m_ThumbBitmap = nil;
902 }
903
904 DEBUG_FUNC_LEAVE();
905}
906
907- (void)lock
908{
909 DEBUG_FUNC_ENTER();
910 [m_Lock lock];
911 DEBUG_FUNC_LEAVE();
912}
913
914- (void)unlock
915{
916 DEBUG_FUNC_ENTER();
917 [m_Lock unlock];
918 DEBUG_FUNC_LEAVE();
919}
920
921- (void)setFrame:(NSRect)frame
922{
923 DEBUG_FUNC_ENTER();
924 [super setFrame:frame];
925
926 [self lock];
927 [self cleanup];
928
929 if ( frame.size.width > 0
930 && frame.size.height > 0)
931 {
932 /* Create a buffer for our thumbnail image. Its in the size of this view. */
933 m_ThumbBitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
934 pixelsWide:frame.size.width
935 pixelsHigh:frame.size.height
936 bitsPerSample:8
937 samplesPerPixel:4
938 hasAlpha:YES
939 isPlanar:NO
940 colorSpaceName:NSDeviceRGBColorSpace
941 bitmapFormat:NSAlphaFirstBitmapFormat
942 bytesPerRow:frame.size.width * 4
943 bitsPerPixel:8 * 4
944 ];
945 m_ThumbImage = [[NSImage alloc] initWithSize:[m_ThumbBitmap size]];
946 [m_ThumbImage addRepresentation:m_ThumbBitmap];
947 }
948
949 [self unlock];
950 DEBUG_FUNC_LEAVE();
951}
952
953- (BOOL)isFlipped
954{
955 DEBUG_FUNC_ENTER();
956 DEBUG_FUNC_LEAVE();
957 return YES;
958}
959
960- (void)drawRect:(NSRect)aRect
961{
962 NSRect frame;
963 DEBUG_FUNC_ENTER();
964 [self lock];
965
966#ifdef SHOW_WINDOW_BACKGROUND
967 [[NSColor colorWithCalibratedRed:1.0 green:0.0 blue:0.0 alpha:0.7] set];
968 frame = [self frame];
969 [NSBezierPath fillRect:NSMakeRect(0, 0, frame.size.width, frame.size.height)];
970#endif /* SHOW_WINDOW_BACKGROUND */
971 if (m_ThumbImage != nil)
972 [m_ThumbImage drawAtPoint:NSMakePoint(0, 0) fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
973
974 [self unlock];
975 DEBUG_FUNC_LEAVE();
976}
977
978- (NSBitmapImageRep *)thumbBitmap
979{
980 DEBUG_FUNC_ENTER();
981 DEBUG_FUNC_LEAVE();
982 return m_ThumbBitmap;
983}
984
985- (NSImage *)thumbImage
986{
987 DEBUG_FUNC_ENTER();
988 DEBUG_FUNC_LEAVE();
989 return m_ThumbImage;
990}
991@end
992
993
994/********************************************************************************
995*
996* OverlayOpenGLContext class implementation
997*
998********************************************************************************/
999@implementation OverlayOpenGLContext
1000
1001-(id)initWithFormat:(NSOpenGLPixelFormat *)format shareContext:(NSOpenGLContext *)share
1002{
1003 DEBUG_FUNC_ENTER();
1004
1005 m_pPixelFormat = NULL;
1006 m_pView = NULL;
1007
1008 self = [super initWithFormat:format shareContext:share];
1009 if (self)
1010 m_pPixelFormat = format;
1011
1012 DEBUG_MSG(("OCTX(%p): init OverlayOpenGLContext\n", (void *)self));
1013 DEBUG_FUNC_LEAVE();
1014 return self;
1015}
1016
1017- (void)dealloc
1018{
1019 DEBUG_FUNC_ENTER();
1020 DEBUG_MSG(("OCTX(%p): dealloc OverlayOpenGLContext\n", (void *)self));
1021
1022 [m_pPixelFormat release];
1023
1024 [super dealloc];
1025
1026 DEBUG_FUNC_LEAVE();
1027}
1028
1029-(bool)isDoubleBuffer
1030{
1031 DEBUG_FUNC_ENTER();
1032
1033 GLint val;
1034 [m_pPixelFormat getValues:&val forAttribute:NSOpenGLPFADoubleBuffer forVirtualScreen:0];
1035
1036 DEBUG_FUNC_LEAVE();
1037 return val == GL_TRUE ? YES : NO;
1038}
1039
1040-(void)setView:(NSView *)view
1041{
1042 DEBUG_FUNC_ENTER();
1043 DEBUG_MSG(("OCTX(%p): setView: new view: %p\n", (void *)self, (void *)view));
1044
1045#if 1 /* def FBO */
1046 m_pView = view;;
1047#else
1048 [super setView: view];
1049#endif
1050
1051 DEBUG_FUNC_LEAVE();
1052}
1053
1054-(NSView *)view
1055{
1056 DEBUG_FUNC_ENTER();
1057 DEBUG_FUNC_LEAVE();
1058#if 1 /* def FBO */
1059 return m_pView;
1060#else
1061 return [super view];
1062#endif
1063}
1064
1065-(void)clearDrawable
1066{
1067 DEBUG_FUNC_ENTER();
1068 DEBUG_MSG(("OCTX(%p): clearDrawable\n", (void *)self));
1069
1070 m_pView = NULL;;
1071 [super clearDrawable];
1072
1073 DEBUG_FUNC_LEAVE();
1074}
1075
1076-(NSOpenGLPixelFormat *)openGLPixelFormat
1077{
1078 DEBUG_FUNC_ENTER();
1079 DEBUG_FUNC_LEAVE();
1080
1081 return m_pPixelFormat;
1082}
1083
1084@end /* @implementation OverlayOpenGLContext */
1085
1086
1087/********************************************************************************
1088*
1089* OverlayHelperView class implementation
1090*
1091********************************************************************************/
1092@implementation OverlayHelperView
1093
1094-(id)initWithOverlayWindow:(OverlayWindow *)pOverlayWindow
1095{
1096 DEBUG_FUNC_ENTER();
1097
1098 self = [super initWithFrame:NSZeroRect];
1099
1100 m_pOverlayWindow = pOverlayWindow;
1101
1102 DEBUG_MSG(("OHVW(%p): init OverlayHelperView\n", (void *)self));
1103 DEBUG_FUNC_LEAVE();
1104 return self;
1105}
1106
1107-(void)viewDidMoveToWindow
1108{
1109 DEBUG_FUNC_ENTER();
1110 DEBUG_MSG(("OHVW(%p): viewDidMoveToWindow: new win: %p\n", (void *)self, (void *)[self window]));
1111
1112 [m_pOverlayWindow parentWindowChanged:[self window]];
1113
1114 DEBUG_FUNC_LEAVE();
1115}
1116
1117@end
1118
1119
1120/********************************************************************************
1121*
1122* OverlayWindow class implementation
1123*
1124********************************************************************************/
1125@implementation OverlayWindow
1126
1127- (id)initWithParentView:(NSView *)pParentView overlayView:(OverlayView *)pOverlayView
1128{
1129 DEBUG_FUNC_ENTER();
1130 NSWindow *pParentWin = nil;
1131
1132 self = [super initWithContentRect:NSZeroRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO];
1133 if (self)
1134 {
1135 m_pParentView = pParentView;
1136 m_pOverlayView = pOverlayView;
1137 m_Thread = [NSThread currentThread];
1138
1139 [m_pOverlayView setOverlayWin: self];
1140
1141 m_pOverlayHelperView = [[OverlayHelperView alloc] initWithOverlayWindow:self];
1142
1143 /* Add the helper view as a child of the parent view to get notifications */
1144 [pParentView addSubview:m_pOverlayHelperView];
1145
1146 /* Make sure this window is transparent */
1147#ifdef SHOW_WINDOW_BACKGROUND
1148 /* For debugging */
1149 [self setBackgroundColor:[NSColor colorWithCalibratedRed:1.0 green:0.0 blue:0.0 alpha:0.7]];
1150#else
1151 [self setBackgroundColor:[NSColor clearColor]];
1152#endif
1153 [self setOpaque:NO];
1154 [self setAlphaValue:.999];
1155
1156 /* Disable mouse events for this window */
1157 [self setIgnoresMouseEvents:YES];
1158
1159 pParentWin = [m_pParentView window];
1160
1161 /* Initial set the position to the parents view top/left (Compiz fix). */
1162 [self setFrameOrigin:
1163 [pParentWin convertBaseToScreen:
1164 [m_pParentView convertPoint:NSZeroPoint toView:nil]]];
1165
1166 /* Set the overlay view as our content view */
1167 [self setContentView:m_pOverlayView];
1168
1169 /* Add ourself as a child to the parent views window. Note: this has to
1170 * be done last so that everything else is setup in
1171 * parentWindowChanged. */
1172 [pParentWin addChildWindow:self ordered:NSWindowAbove];
1173 }
1174
1175 DEBUG_MSG(("OWIN(%p): init OverlayWindow\n", (void *)self));
1176 DEBUG_FUNC_LEAVE();
1177 return self;
1178}
1179
1180- (void)dealloc
1181{
1182 DEBUG_FUNC_ENTER();
1183 DEBUG_MSG(("OWIN(%p): dealloc OverlayWindow\n", (void *)self));
1184
1185 [[NSNotificationCenter defaultCenter] removeObserver:self];
1186
1187 [m_pOverlayHelperView removeFromSuperview];
1188 [m_pOverlayHelperView release];
1189
1190 [super dealloc];
1191
1192 DEBUG_FUNC_LEAVE();
1193}
1194
1195- (void)parentWindowFrameChanged:(NSNotification *)pNote
1196{
1197 DEBUG_FUNC_ENTER();
1198 DEBUG_MSG(("OWIN(%p): parentWindowFrameChanged\n", (void *)self));
1199
1200 /*
1201 * Reposition this window with the help of the OverlayView. Perform the
1202 * call in the OpenGL thread.
1203 */
1204 /*
1205 [m_pOverlayView performSelector:@selector(vboxReshapePerform) onThread:m_Thread withObject:nil waitUntilDone:YES];
1206 */
1207
1208 if ([m_pOverlayView isEverSized])
1209 {
1210 if ([NSThread isMainThread])
1211 [m_pOverlayView vboxReshapePerform];
1212 else
1213 [self performSelectorOnMainThread:@selector(vboxReshapePerform) withObject:nil waitUntilDone:NO];
1214 }
1215
1216 DEBUG_FUNC_LEAVE();
1217}
1218
1219- (void)parentWindowChanged:(NSWindow *)pWindow
1220{
1221 DEBUG_FUNC_ENTER();
1222 DEBUG_MSG(("OWIN(%p): parentWindowChanged\n", (void *)self));
1223
1224 [[NSNotificationCenter defaultCenter] removeObserver:self];
1225
1226 if (pWindow != nil)
1227 {
1228 /* Ask to get notifications when our parent window frame changes. */
1229 [[NSNotificationCenter defaultCenter]
1230 addObserver:self
1231 selector:@selector(parentWindowFrameChanged:)
1232 name:NSWindowDidResizeNotification
1233 object:pWindow];
1234
1235 /* Add us self as child window */
1236 [pWindow addChildWindow:self ordered:NSWindowAbove];
1237
1238 /*
1239 * Reshape the overlay view after a short waiting time to let the main
1240 * window resize itself properly.
1241 */
1242 /*
1243 [m_pOverlayView performSelector:@selector(vboxReshapePerform) withObject:nil afterDelay:0.2];
1244 [NSTimer scheduledTimerWithTimeInterval:0.2 target:m_pOverlayView selector:@selector(vboxReshapePerform) userInfo:nil repeats:NO];
1245 */
1246
1247 if ([m_pOverlayView isEverSized])
1248 {
1249 if ([NSThread isMainThread])
1250 [m_pOverlayView vboxReshapePerform];
1251 else
1252 [self performSelectorOnMainThread:@selector(vboxReshapePerform) withObject:nil waitUntilDone:NO];
1253 }
1254 }
1255
1256 DEBUG_FUNC_LEAVE();
1257}
1258
1259@end /* @implementation OverlayWindow */
1260
1261
1262
1263/********************************************************************************
1264*
1265* OverlayView class implementation
1266*
1267********************************************************************************/
1268@implementation OverlayView
1269
1270- (id)initWithFrame:(NSRect)frame thread:(RTTHREAD)aThread parentView:(NSView *)pParentView winInfo:(WindowInfo *)pWinInfo
1271{
1272 DEBUG_FUNC_ENTER();
1273
1274 m_pParentView = pParentView;
1275 /* Make some reasonable defaults */
1276 m_pGLCtx = nil;
1277 m_pSharedGLCtx = nil;
1278 m_Thread = aThread;
1279 m_FBOId = 0;
1280 m_cClipRects = 0;
1281 m_paClipRects = NULL;
1282 m_Pos = NSZeroPoint;
1283 m_Size = NSMakeSize(1, 1);
1284 m_RootRect = NSMakeRect(0, 0, m_Size.width, m_Size.height);
1285 m_yInvRootOffset = 0;
1286 m_pBlitter = nil;
1287 m_pWinInfo = pWinInfo;
1288 m_fNeedViewportUpdate = true;
1289 m_fNeedCtxUpdate = true;
1290 m_fDataVisible = false;
1291 m_fCleanupNeeded = false;
1292 m_fEverSized = false;
1293
1294 self = [super initWithFrame:frame];
1295
1296 DEBUG_MSG(("OVIW(%p): init OverlayView\n", (void *)self));
1297 DEBUG_FUNC_LEAVE();
1298 return self;
1299}
1300
1301- (void)cleanupData
1302{
1303 DEBUG_FUNC_ENTER();
1304
1305 [self deleteDockTile];
1306
1307 [self setGLCtx:nil];
1308
1309 if (m_pSharedGLCtx)
1310 {
1311 if ([m_pSharedGLCtx view] == self)
1312 [m_pSharedGLCtx clearDrawable];
1313
1314 [m_pSharedGLCtx release];
1315 m_pSharedGLCtx = nil;
1316
1317 CrBltTerm(m_pBlitter);
1318 RTMemFree(m_pBlitter);
1319 m_pBlitter = nil;
1320 }
1321
1322 [self clearVisibleRegions];
1323
1324 DEBUG_FUNC_LEAVE();
1325}
1326
1327- (void)dealloc
1328{
1329 DEBUG_FUNC_ENTER();
1330 DEBUG_MSG(("OVIW(%p): dealloc OverlayView\n", (void *)self));
1331
1332 [self cleanupData];
1333 [super dealloc];
1334
1335 DEBUG_FUNC_LEAVE();
1336}
1337
1338- (void)drawRect:(NSRect)aRect
1339{
1340 [self vboxTryDrawUI];
1341}
1342
1343- (void)setGLCtx:(NSOpenGLContext *)pCtx
1344{
1345 DEBUG_FUNC_ENTER();
1346 DEBUG_MSG(("OVIW(%p): setGLCtx: new ctx: %p\n", (void *)self, (void *)pCtx));
1347
1348 /*
1349 * Only do something if the context changes.
1350 */
1351 if (m_pGLCtx != pCtx)
1352 {
1353 /* Ensure the context drawable is cleared to avoid holding a reference to inexistent view. */
1354 if (m_pGLCtx)
1355 {
1356 [m_pGLCtx clearDrawable];
1357 [m_pGLCtx release];
1358 /*[m_pGLCtx performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO];*/
1359 }
1360
1361 m_pGLCtx = pCtx;
1362 if (pCtx)
1363 [pCtx retain];
1364 }
1365
1366 DEBUG_FUNC_LEAVE();
1367}
1368
1369- (NSOpenGLContext *)glCtx
1370{
1371 DEBUG_FUNC_ENTER();
1372 DEBUG_FUNC_LEAVE();
1373 return m_pGLCtx;
1374}
1375
1376- (NSView *)parentView
1377{
1378 DEBUG_FUNC_ENTER();
1379 DEBUG_FUNC_LEAVE();
1380 return m_pParentView;
1381}
1382
1383- (void)setParentView:(NSView *)pView
1384{
1385 DEBUG_FUNC_ENTER();
1386 DEBUG_MSG(("OVIW(%p): setParentView: new view: %p\n", (void *)self, (void *)pView));
1387
1388 m_pParentView = pView;
1389
1390 DEBUG_FUNC_LEAVE();
1391}
1392
1393- (void)setOverlayWin:(NSWindow *)pWin
1394{
1395 DEBUG_FUNC_ENTER();
1396 DEBUG_MSG(("OVIW(%p): setOverlayWin: new win: %p\n", (void *)self, (void *)pWin));
1397
1398 m_pOverlayWin = pWin;
1399
1400 DEBUG_FUNC_LEAVE();
1401}
1402
1403- (NSWindow *)overlayWin
1404{
1405 DEBUG_FUNC_ENTER();
1406 DEBUG_FUNC_LEAVE();
1407 return m_pOverlayWin;
1408}
1409
1410- (void)vboxSetPosUI:(NSPoint)pos
1411{
1412 DEBUG_FUNC_ENTER();
1413
1414 m_Pos = pos;
1415
1416 if (m_fEverSized)
1417 [self vboxReshapePerform];
1418
1419 DEBUG_FUNC_LEAVE();
1420}
1421
1422- (void)vboxSetPosUIObj:(NSValue *)pPos
1423{
1424 DEBUG_FUNC_ENTER();
1425
1426 NSPoint pos = [pPos pointValue];
1427 [self vboxSetPosUI:pos];
1428
1429 DEBUG_FUNC_LEAVE();
1430}
1431
1432- (void)vboxSetPos:(NSPoint)pos
1433{
1434 DEBUG_FUNC_ENTER();
1435
1436 DEBUG_MSG(("OVIW(%p): vboxSetPos: new pos: %d, %d\n", (void *)self, (int)pos.x, (int)pos.y));
1437 VBoxMainThreadTaskRunner *pRunner = [VBoxMainThreadTaskRunner globalInstance];
1438 NSValue *pPos = [NSValue valueWithPoint:pos];
1439 [pRunner addObj:self selector:@selector(vboxSetPosUIObj:) arg:pPos];
1440
1441 DEBUG_FUNC_LEAVE();
1442}
1443
1444- (NSPoint)pos
1445{
1446 DEBUG_FUNC_ENTER();
1447 DEBUG_FUNC_LEAVE();
1448 return m_Pos;
1449}
1450
1451- (bool)isEverSized
1452{
1453 DEBUG_FUNC_ENTER();
1454 DEBUG_FUNC_LEAVE();
1455 return m_fEverSized;
1456}
1457
1458- (void)vboxDestroy
1459{
1460 DEBUG_FUNC_ENTER();
1461 BOOL fIsMain = [NSThread isMainThread];
1462 NSWindow *pWin = nil;
1463
1464 Assert(fIsMain);
1465
1466 /* Hide the view early. */
1467 [self setHidden: YES];
1468
1469 pWin = [self window];
1470 [[NSNotificationCenter defaultCenter] removeObserver:pWin];
1471 [pWin setContentView: nil];
1472 [[pWin parentWindow] removeChildWindow: pWin];
1473
1474 if (fIsMain)
1475 [pWin release];
1476 else
1477 {
1478 /* We can NOT run synchronously with the main thread since this may lead to a deadlock,
1479 caused by main thread waiting xpcom thread, xpcom thread waiting to main hgcm thread,
1480 and main hgcm thread waiting for us, this is why use waitUntilDone:NO,
1481 which should cause no harm. */
1482 [pWin performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO];
1483 }
1484
1485 [self cleanupData];
1486
1487 if (fIsMain)
1488 [self release];
1489 else
1490 {
1491 /* We can NOT run synchronously with the main thread since this may lead to a deadlock,
1492 caused by main thread waiting xpcom thread, xpcom thread waiting to main hgcm thread,
1493 and main hgcm thread waiting for us, this is why use waitUntilDone:NO.
1494 We need to avoid concurrency though, so we cleanup some data right away via a cleanupData call. */
1495 [self performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO];
1496 }
1497
1498 renderspuWinRelease(m_pWinInfo);
1499
1500 DEBUG_FUNC_LEAVE();
1501}
1502
1503- (void)vboxSetSizeUIObj:(NSValue *)pSize
1504{
1505 DEBUG_FUNC_ENTER();
1506 NSSize size = [pSize sizeValue];
1507 [self vboxSetSizeUI:size];
1508 DEBUG_FUNC_LEAVE();
1509}
1510
1511- (void)vboxSetSizeUI:(NSSize)size
1512{
1513 DEBUG_FUNC_ENTER();
1514
1515 m_Size = size;
1516 m_fEverSized = true;
1517
1518 DEBUG_MSG(("OVIW(%p): vboxSetSize: new size: %dx%d\n", (void *)self, (int)m_Size.width, (int)m_Size.height));
1519 [self vboxReshapeOnResizePerform];
1520
1521 /* ensure window contents is updated after that */
1522 [self vboxTryDrawUI];
1523
1524 DEBUG_FUNC_LEAVE();
1525}
1526
1527- (void)vboxSetSize:(NSSize)size
1528{
1529 DEBUG_FUNC_ENTER();
1530
1531 VBoxMainThreadTaskRunner *pRunner = [VBoxMainThreadTaskRunner globalInstance];
1532 NSValue *pSize = [NSValue valueWithSize:size];
1533 [pRunner addObj:self selector:@selector(vboxSetSizeUIObj:) arg:pSize];
1534
1535 DEBUG_FUNC_LEAVE();
1536}
1537
1538- (NSSize)size
1539{
1540 DEBUG_FUNC_ENTER();
1541 DEBUG_FUNC_LEAVE();
1542 return m_Size;
1543}
1544
1545- (void)updateViewportCS
1546{
1547 DEBUG_FUNC_ENTER();
1548 DEBUG_MSG(("OVIW(%p): updateViewport\n", (void *)self));
1549
1550 /* Update the viewport for our OpenGL view. */
1551 [m_pSharedGLCtx update];
1552
1553 [self vboxBlitterSyncWindow];
1554
1555 /* Clear background to transparent. */
1556 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
1557 DEBUG_FUNC_LEAVE();
1558}
1559
1560- (void)vboxReshapeOnResizePerform
1561{
1562 DEBUG_FUNC_ENTER();
1563
1564 [self vboxReshapePerform];
1565 [self createDockTile];
1566
1567 /* have to rebind GL_TEXTURE_RECTANGLE_ARB as m_FBOTexId could be changed in updateFBO call */
1568 m_fNeedViewportUpdate = true;
1569#if 0
1570 pCurCtx = [NSOpenGLContext currentContext];
1571 if (pCurCtx && pCurCtx == m_pGLCtx && (pCurView = [pCurCtx view]) == self)
1572 {
1573 [m_pGLCtx update];
1574 m_fNeedCtxUpdate = false;
1575 }
1576 else
1577 {
1578 /* do it in a lazy way */
1579 m_fNeedCtxUpdate = true;
1580 }
1581#endif
1582
1583 DEBUG_FUNC_LEAVE();
1584}
1585
1586- (void)vboxReshapeOnReparentPerform
1587{
1588 DEBUG_FUNC_ENTER();
1589 [self createDockTile];
1590 DEBUG_FUNC_LEAVE();
1591}
1592
1593- (void)vboxReshapePerform
1594{
1595 DEBUG_FUNC_ENTER();
1596 NSRect parentFrame = NSZeroRect;
1597 NSPoint parentPos = NSZeroPoint;
1598 NSPoint childPos = NSZeroPoint;
1599 NSRect childFrame = NSZeroRect;
1600 NSRect newFrame = NSZeroRect;
1601
1602 DEBUG_MSG(("OVIW(%p): vboxReshapePerform\n", (void *)self));
1603
1604 parentFrame = [m_pParentView frame];
1605 DEBUG_MSG(("FIXED parentFrame [%f:%f], [%f:%f]\n", parentFrame.origin.x, parentFrame.origin.y, parentFrame.size.width, parentFrame.size.height));
1606 parentPos = parentFrame.origin;
1607 parentPos.y += parentFrame.size.height;
1608 DEBUG_MSG(("FIXED(view) parentPos [%f:%f]\n", parentPos.x, parentPos.y));
1609 parentPos = [m_pParentView convertPoint:parentPos toView:nil];
1610 DEBUG_MSG(("FIXED parentPos(win) [%f:%f]\n", parentPos.x, parentPos.y));
1611 parentPos = [[m_pParentView window] convertBaseToScreen:parentPos];
1612 DEBUG_MSG(("FIXED parentPos(screen) [%f:%f]\n", parentPos.x, parentPos.y));
1613 parentFrame.origin = parentPos;
1614
1615 childPos = NSMakePoint(m_Pos.x, m_Pos.y + m_Size.height);
1616 DEBUG_MSG(("FIXED(view) childPos [%f:%f]\n", childPos.x, childPos.y));
1617 childPos = [m_pParentView convertPoint:childPos toView:nil];
1618 DEBUG_MSG(("FIXED(win) childPos [%f:%f]\n", childPos.x, childPos.y));
1619 childPos = [[m_pParentView window] convertBaseToScreen:childPos];
1620 DEBUG_MSG(("FIXED childPos(screen) [%f:%f]\n", childPos.x, childPos.y));
1621 childFrame = NSMakeRect(childPos.x, childPos.y, m_Size.width, m_Size.height);
1622 DEBUG_MSG(("FIXED childFrame [%f:%f], [%f:%f]\n", childFrame.origin.x, childFrame.origin.y, childFrame.size.width, childFrame.size.height));
1623
1624 /* We have to make sure that the overlay window will not be displayed out
1625 * of the parent window. So intersect both frames & use the result as the new
1626 * frame for the window. */
1627 newFrame = NSIntersectionRect(parentFrame, childFrame);
1628
1629 DEBUG_MSG(("[%#p]: parentFrame pos[%f : %f] size[%f : %f]\n",
1630 (void *)self, parentFrame.origin.x, parentFrame.origin.y, parentFrame.size.width, parentFrame.size.height));
1631 DEBUG_MSG(("[%#p]: childFrame pos[%f : %f] size[%f : %f]\n",
1632 (void *)self, childFrame.origin.x, childFrame.origin.y, childFrame.size.width, childFrame.size.height));
1633
1634 DEBUG_MSG(("[%#p]: newFrame pos[%f : %f] size[%f : %f]\n",
1635 (void *)self, newFrame.origin.x, newFrame.origin.y, newFrame.size.width, newFrame.size.height));
1636
1637 /* Later we have to correct the texture position in the case the window is
1638 * out of the parents window frame. So save the shift values for later use. */
1639 m_RootRect.origin.x = newFrame.origin.x - childFrame.origin.x;
1640 m_RootRect.origin.y = childFrame.size.height + childFrame.origin.y - (newFrame.size.height + newFrame.origin.y);
1641 m_RootRect.size = newFrame.size;
1642 m_yInvRootOffset = newFrame.origin.y - childFrame.origin.y;
1643
1644 DEBUG_MSG(("[%#p]: m_RootRect pos[%f : %f] size[%f : %f]\n",
1645 (void *)self, m_RootRect.origin.x, m_RootRect.origin.y, m_RootRect.size.width, m_RootRect.size.height));
1646
1647
1648 /*
1649 NSScrollView *pScrollView = [[[m_pParentView window] contentView] enclosingScrollView];
1650 if (pScrollView)
1651 {
1652 NSRect scrollRect = [pScrollView documentVisibleRect];
1653 NSRect scrollRect = [m_pParentView visibleRect];
1654 printf ("sc rect: %d %d %d %d\n", (int) scrollRect.origin.x,(int) scrollRect.origin.y,(int) scrollRect.size.width,(int) scrollRect.size.height);
1655 NSRect b = [[m_pParentView superview] bounds];
1656 printf ("bound rect: %d %d %d %d\n", (int) b.origin.x,(int) b.origin.y,(int) b.size.width,(int) b.size.height);
1657 newFrame.origin.x += scrollRect.origin.x;
1658 newFrame.origin.y += scrollRect.origin.y;
1659 }
1660 */
1661
1662 /* Set the new frame. */
1663 [[self window] setFrame:newFrame display:YES];
1664
1665 /* Inform the dock tile view as well. */
1666 [self reshapeDockTile];
1667
1668 /* Make sure the context is updated accordingly. */
1669 /* [self updateViewport]; */
1670 if (m_pSharedGLCtx)
1671 {
1672 VBOX_CR_RENDER_CTX_INFO CtxInfo;
1673 vboxCtxEnter(m_pSharedGLCtx, &CtxInfo);
1674
1675 [self updateViewportCS];
1676
1677 vboxCtxLeave(&CtxInfo);
1678 }
1679
1680 DEBUG_FUNC_LEAVE();
1681}
1682
1683- (void)createDockTile
1684{
1685 DEBUG_FUNC_ENTER();
1686 NSView *pDockScreen = nil;
1687
1688 [self deleteDockTile];
1689
1690 /* Is there a dock tile preview enabled in the GUI? If so setup a
1691 * additional thumbnail view for the dock tile. */
1692 pDockScreen = [self dockTileScreen];
1693 if (pDockScreen)
1694 {
1695 m_DockTileView = [[DockOverlayView alloc] init];
1696 [self reshapeDockTile];
1697 [pDockScreen addSubview:m_DockTileView];
1698 }
1699
1700 DEBUG_FUNC_LEAVE();
1701}
1702
1703- (void)deleteDockTile
1704{
1705 DEBUG_FUNC_ENTER();
1706 if (m_DockTileView != nil)
1707 {
1708 [m_DockTileView removeFromSuperview];
1709 [m_DockTileView release];
1710 m_DockTileView = nil;
1711 }
1712 DEBUG_FUNC_LEAVE();
1713}
1714
1715- (void)makeCurrentFBO
1716{
1717 DEBUG_MSG(("OVIW(%p): makeCurrentFBO\n", (void *)self));
1718
1719 if (m_pGLCtx)
1720 {
1721 if ([m_pGLCtx view] != self)
1722 {
1723 /* We change the active view, so flush first */
1724 if ([NSOpenGLContext currentContext] != 0)
1725 glFlush();
1726 [m_pGLCtx setView: self];
1727 DEBUG_CHECK_GL_ERROR();
1728 }
1729 /*
1730 if ([NSOpenGLContext currentContext] != m_pGLCtx)
1731 */
1732 {
1733 [m_pGLCtx makeCurrentContext];
1734 DEBUG_CHECK_GL_ERROR();
1735 if (m_fNeedCtxUpdate == true)
1736 {
1737 [m_pGLCtx update];
1738 m_fNeedCtxUpdate = false;
1739 }
1740 }
1741
1742 if (!m_FBOId)
1743 {
1744 glGenFramebuffersEXT(1, &m_FBOId);
1745 Assert(m_FBOId);
1746 }
1747 }
1748}
1749
1750- (bool)vboxSharedCtxCreate
1751{
1752 DEBUG_FUNC_ENTER();
1753 GLint opaque = 0;
1754 NSOpenGLContext *pSharedGLCtx;
1755 NSOpenGLPixelFormat *pPixelFormat;
1756
1757 if (m_pSharedGLCtx)
1758 {
1759 DEBUG_FUNC_LEAVE();
1760 return true;
1761 }
1762
1763 Assert(!m_pBlitter);
1764 m_pBlitter = RTMemAlloc(sizeof (*m_pBlitter));
1765 if (RT_UNLIKELY(!m_pBlitter))
1766 {
1767 DEBUG_WARN(("m_pBlitter allocation failed"));
1768 DEBUG_FUNC_LEAVE();
1769 return false;
1770 }
1771
1772 int rc = CrBltInit(m_pBlitter, NULL, false, false, &render_spu.GlobalShaders, &render_spu.blitterDispatch);
1773 if (RT_FAILURE(rc))
1774 {
1775 DEBUG_WARN(("CrBltInit failed, rc %d", rc));
1776 RTMemFree(m_pBlitter);
1777 m_pBlitter = NULL;
1778 DEBUG_FUNC_LEAVE();
1779 return false;
1780 }
1781
1782 DEBUG_MSG(("blitter created successfully for view 0x%p\n", (void *)self));
1783
1784 /* Create a shared context out of the main context. Use the same pixel format. */
1785 pPixelFormat = [(OverlayOpenGLContext *)m_pGLCtx openGLPixelFormat];
1786 pSharedGLCtx = [[NSOpenGLContext alloc] initWithFormat:pPixelFormat shareContext:m_pGLCtx];
1787
1788 /* Set the new context as non opaque */
1789 [pSharedGLCtx setValues:&opaque forParameter:NSOpenGLCPSurfaceOpacity];
1790
1791 /* Set this view as the drawable for the new context */
1792 [pSharedGLCtx setView:self];
1793 m_fNeedViewportUpdate = true;
1794
1795 m_pSharedGLCtx = pSharedGLCtx;
1796
1797 DEBUG_FUNC_LEAVE();
1798 return true;
1799}
1800
1801- (void)vboxTryDraw
1802{
1803 glFlush();
1804
1805 /* Issue to the gui thread. */
1806 DEBUG_MSG(("My[%p]: Draw\n", self));
1807 [self performSelectorOnMainThread:@selector(vboxTryDrawUI) withObject:nil waitUntilDone:NO];
1808}
1809
1810- (void)vboxSetVisible:(GLboolean)fVisible
1811{
1812 DEBUG_FUNC_ENTER();
1813
1814 VBoxMainThreadTaskRunner *pRunner = [VBoxMainThreadTaskRunner globalInstance];
1815 NSNumber* pVisObj = [NSNumber numberWithBool:fVisible];
1816 [pRunner addObj:self selector:@selector(vboxSetVisibleUIObj:) arg:pVisObj];
1817
1818 DEBUG_FUNC_LEAVE();
1819}
1820
1821- (void)vboxSetVisibleUI:(GLboolean)fVisible
1822{
1823 DEBUG_FUNC_ENTER();
1824 [self setHidden: !fVisible];
1825 DEBUG_FUNC_LEAVE();
1826}
1827
1828- (void)vboxSetVisibleUIObj:(NSNumber*)pVisible
1829{
1830 DEBUG_FUNC_ENTER();
1831 BOOL fVisible = [pVisible boolValue];
1832 [self vboxSetVisibleUI:fVisible];
1833 DEBUG_FUNC_LEAVE();
1834}
1835
1836- (void)vboxReparent:(NSView *)pParentView
1837{
1838 DEBUG_FUNC_ENTER();
1839
1840 VBoxMainThreadTaskRunner *pRunner = [VBoxMainThreadTaskRunner globalInstance];
1841 [pRunner addObj:self selector:@selector(vboxReparentUI:) arg:pParentView];
1842
1843 DEBUG_FUNC_LEAVE();
1844}
1845
1846- (void)vboxReparentUI:(NSView *)pParentView
1847{
1848 DEBUG_FUNC_ENTER();
1849
1850 /* Make sure the window is removed from any previous parent window. */
1851 if ([[self overlayWin] parentWindow] != nil)
1852 {
1853 [[[self overlayWin] parentWindow] removeChildWindow:[self overlayWin]];
1854 }
1855
1856 /* Set the new parent view */
1857 [self setParentView: pParentView];
1858
1859 /* Add the overlay window as a child to the new parent window */
1860 if (pParentView != nil)
1861 {
1862 [[pParentView window] addChildWindow:[self overlayWin] ordered:NSWindowAbove];
1863 if ([self isEverSized])
1864 [self vboxReshapeOnReparentPerform];
1865 }
1866
1867 DEBUG_FUNC_LEAVE();
1868}
1869
1870- (void)vboxTryDrawUI
1871{
1872 const VBOXVR_SCR_COMPOSITOR *pCompositor;
1873 DEBUG_MSG(("My[%p]: DrawUI\n", self));
1874
1875 if ([self isHidden])
1876 {
1877 DEBUG_INFO(("request to draw on a hidden view"));
1878 return;
1879 }
1880
1881 if ([[self overlayWin] parentWindow] == nil)
1882 {
1883 DEBUG_INFO(("request to draw a view w/o a parent"));
1884 return;
1885 }
1886
1887 int rc = renderspuVBoxCompositorLock(m_pWinInfo, &pCompositor);
1888 if (RT_FAILURE(rc))
1889 {
1890 DEBUG_WARN(("renderspuVBoxCompositorLock failed\n"));
1891 return;
1892 }
1893
1894 if (!pCompositor && !m_fCleanupNeeded)
1895 {
1896 DEBUG_MSG(("My[%p]: noCompositorUI\n", self));
1897 renderspuVBoxCompositorUnlock(m_pWinInfo);
1898 return;
1899 }
1900
1901 VBOXVR_SCR_COMPOSITOR TmpCompositor;
1902
1903 if (pCompositor)
1904 {
1905 if (!m_pSharedGLCtx)
1906 {
1907 Assert(!m_fDataVisible);
1908 Assert(!m_fCleanupNeeded);
1909 renderspuVBoxCompositorRelease(m_pWinInfo);
1910 if (![self vboxSharedCtxCreate])
1911 {
1912 DEBUG_WARN(("vboxSharedCtxCreate failed\n"));
1913 return;
1914 }
1915
1916 Assert(m_pSharedGLCtx);
1917
1918 pCompositor = renderspuVBoxCompositorAcquire(m_pWinInfo);
1919 Assert(!m_fDataVisible);
1920 Assert(!m_fCleanupNeeded);
1921 if (!pCompositor)
1922 return;
1923 }
1924 }
1925 else
1926 {
1927 DEBUG_MSG(("My[%p]: NeedCleanup\n", self));
1928 Assert(m_fCleanupNeeded);
1929 CrVrScrCompositorInit(&TmpCompositor, NULL);
1930 pCompositor = &TmpCompositor;
1931 }
1932
1933 if ([self lockFocusIfCanDraw])
1934 {
1935 [self vboxPresent:pCompositor];
1936 [self unlockFocus];
1937 }
1938 else if (!m_pWinInfo->visible)
1939 {
1940 DEBUG_MSG(("My[%p]: NotVisible\n", self));
1941 m_fCleanupNeeded = false;
1942 }
1943 else
1944 {
1945 DEBUG_MSG(("My[%p]: Reschedule\n", self));
1946 [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(vboxTryDrawUI) userInfo:nil repeats:NO];
1947 }
1948
1949 renderspuVBoxCompositorUnlock(m_pWinInfo);
1950}
1951
1952- (void)swapFBO
1953{
1954 DEBUG_FUNC_ENTER();
1955 [m_pGLCtx flushBuffer];
1956 DEBUG_FUNC_LEAVE();
1957}
1958
1959- (void)vboxPresent:(const VBOXVR_SCR_COMPOSITOR*)pCompositor
1960{
1961 VBOX_CR_RENDER_CTX_INFO CtxInfo;
1962 DEBUG_MSG(("OVIW(%p): renderFBOToView\n", (void *)self));
1963
1964 Assert(pCompositor);
1965
1966 vboxCtxEnter(m_pSharedGLCtx, &CtxInfo);
1967
1968 [self vboxPresentCS:pCompositor];
1969
1970 vboxCtxLeave(&CtxInfo);
1971}
1972
1973- (void)vboxPresentCS:(const VBOXVR_SCR_COMPOSITOR *)pCompositor
1974{
1975 if ([m_pSharedGLCtx view] != self)
1976 {
1977 DEBUG_MSG(("OVIW(%p): not current view of shared ctx! Switching ...\n", (void *)self));
1978 [m_pSharedGLCtx setView: self];
1979 m_fNeedViewportUpdate = true;
1980 }
1981
1982 if (m_fNeedViewportUpdate)
1983 {
1984 [self updateViewportCS];
1985 m_fNeedViewportUpdate = false;
1986 }
1987
1988 m_fCleanupNeeded = false;
1989
1990 /* Render FBO content to the dock tile when necessary. */
1991 [self vboxPresentToDockTileCS:pCompositor];
1992
1993 /* change to #if 0 to see thumbnail image */
1994#if 1
1995 [self vboxPresentToViewCS:pCompositor];
1996#else
1997 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1998 [m_pSharedGLCtx flushBuffer];
1999#endif
2000}
2001
2002DECLINLINE(void) vboxNSRectToRect(const NSRect *pR, RTRECT *pRect)
2003{
2004 pRect->xLeft = (int)pR->origin.x;
2005 pRect->yTop = (int)pR->origin.y;
2006 pRect->xRight = (int)(pR->origin.x + pR->size.width);
2007 pRect->yBottom = (int)(pR->origin.y + pR->size.height);
2008}
2009
2010DECLINLINE(void) vboxNSRectToRectUnstretched(const NSRect *pR, RTRECT *pRect, float xStretch, float yStretch)
2011{
2012 pRect->xLeft = (int)(pR->origin.x / xStretch);
2013 pRect->yTop = (int)(pR->origin.y / yStretch);
2014 pRect->xRight = (int)((pR->origin.x + pR->size.width) / xStretch);
2015 pRect->yBottom = (int)((pR->origin.y + pR->size.height) / yStretch);
2016}
2017
2018DECLINLINE(void) vboxNSRectToRectStretched(const NSRect *pR, RTRECT *pRect, float xStretch, float yStretch)
2019{
2020 pRect->xLeft = (int)(pR->origin.x * xStretch);
2021 pRect->yTop = (int)(pR->origin.y * yStretch);
2022 pRect->xRight = (int)((pR->origin.x + pR->size.width) * xStretch);
2023 pRect->yBottom = (int)((pR->origin.y + pR->size.height) * yStretch);
2024}
2025
2026- (void)vboxPresentToViewCS:(const VBOXVR_SCR_COMPOSITOR*)pCompositor
2027{
2028 NSRect r = [self frame];
2029 float xStretch;
2030 float yStretch;
2031 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));
2032
2033#if 1 /* Set to 0 to see the docktile instead of the real output */
2034 VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR CIter;
2035 const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry;
2036
2037 CrVrScrCompositorConstIterInit(pCompositor, &CIter);
2038
2039 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
2040 glDrawBuffer(GL_BACK);
2041
2042 /* Clear background to transparent */
2043 glClear(GL_COLOR_BUFFER_BIT);
2044
2045 m_fDataVisible = false;
2046
2047 CrVrScrCompositorGetStretching(pCompositor, &xStretch, &yStretch);
2048
2049 while ((pEntry = CrVrScrCompositorConstIterNext(&CIter)) != NULL)
2050 {
2051 uint32_t cRegions;
2052 const RTRECT *paSrcRegions, *paDstRegions;
2053 int rc = CrVrScrCompositorEntryRegionsGet(pCompositor, pEntry, &cRegions, &paSrcRegions, &paDstRegions, NULL);
2054 uint32_t fFlags = CrVrScrCompositorEntryFlagsCombinedGet(pCompositor, pEntry);
2055 if (RT_SUCCESS(rc))
2056 {
2057 rc = CrBltEnter(m_pBlitter);
2058 if (RT_SUCCESS(rc))
2059 {
2060 uint32_t i;
2061 for (i = 0; i < cRegions; ++i)
2062 {
2063 const CR_TEXDATA *pTexData;
2064 PCRTRECT pSrcRect = &paSrcRegions[i];
2065 PCRTRECT pDstRect = &paDstRegions[i];
2066 RTRECT DstRect, RestrictDstRect;
2067 RTRECT SrcRect, RestrictSrcRect;
2068
2069 vboxNSRectToRect(&m_RootRect, &RestrictDstRect);
2070 VBoxRectIntersected(&RestrictDstRect, pDstRect, &DstRect);
2071
2072 if (VBoxRectIsZero(&DstRect))
2073 continue;
2074
2075 VBoxRectTranslate(&DstRect, -RestrictDstRect.xLeft, -RestrictDstRect.yTop);
2076
2077 vboxNSRectToRectUnstretched(&m_RootRect, &RestrictSrcRect, xStretch, yStretch);
2078 VBoxRectTranslate(&RestrictSrcRect,
2079 -CrVrScrCompositorEntryRectGet(pEntry)->xLeft,
2080 -CrVrScrCompositorEntryRectGet(pEntry)->yTop);
2081 VBoxRectIntersected(&RestrictSrcRect, pSrcRect, &SrcRect);
2082
2083 if (VBoxRectIsZero(&SrcRect))
2084 continue;
2085
2086 pSrcRect = &SrcRect;
2087 pDstRect = &DstRect;
2088
2089 pTexData = CrVrScrCompositorEntryTexGet(pEntry);
2090
2091 CrBltBlitTexMural(m_pBlitter, true, CrTdTexGet(pTexData), pSrcRect, pDstRect, 1, fFlags | CRBLT_F_NOALPHA);
2092
2093 m_fDataVisible = true;
2094 }
2095 CrBltLeave(m_pBlitter);
2096 }
2097 else
2098 {
2099 DEBUG_WARN(("CrBltEnter failed rc %d", rc));
2100# ifndef DEBUG_VERBOSE
2101 AssertMsgFailed(("CrBltEnter failed rc %Rrc", rc));
2102# endif
2103 }
2104 }
2105 else
2106 {
2107 AssertMsgFailed(("BlitStretched: CrVrScrCompositorEntryRegionsGet failed rc %Rrc\n", rc));
2108 DEBUG_MSG_1(("BlitStretched: CrVrScrCompositorEntryRegionsGet failed rc %d\n", rc));
2109 }
2110 }
2111#endif
2112
2113 /*
2114 glFinish();
2115 */
2116 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
2117 [m_pSharedGLCtx flushBuffer];
2118}
2119
2120- (void)presentComposition:(const VBOXVR_SCR_COMPOSITOR_ENTRY *)pChangedEntry
2121{
2122 [self vboxTryDraw];
2123}
2124
2125- (void)vboxBlitterSyncWindow
2126{
2127 CR_BLITTER_WINDOW WinInfo;
2128 NSRect r;
2129
2130 if (!m_pBlitter)
2131 return;
2132
2133 RT_ZERO(WinInfo);
2134
2135 r = [self frame];
2136 WinInfo.width = r.size.width;
2137 WinInfo.height = r.size.height;
2138
2139 Assert(WinInfo.width == m_RootRect.size.width);
2140 Assert(WinInfo.height == m_RootRect.size.height);
2141
2142 /*CrBltMuralSetCurrentInfo(m_pBlitter, NULL);*/
2143
2144 CrBltMuralSetCurrentInfo(m_pBlitter, &WinInfo);
2145 CrBltCheckUpdateViewport(m_pBlitter);
2146}
2147
2148#ifdef VBOX_WITH_CRDUMPER_THUMBNAIL
2149static int g_cVBoxTgaCtr = 0;
2150#endif
2151- (void)vboxPresentToDockTileCS:(const VBOXVR_SCR_COMPOSITOR*)pCompositor
2152{
2153 NSRect r = [self frame];
2154 NSRect rr = NSZeroRect;
2155 GLint i = 0;
2156 NSDockTile *pDT = nil;
2157 float xStretch;
2158 float yStretch;
2159
2160 if ([m_DockTileView thumbBitmap] != nil)
2161 {
2162 /*
2163 * Only update after at least 200 ms, cause glReadPixels is
2164 * heavy performance wise.
2165 */
2166 uint64_t msTS = RTTimeSystemMilliTS();
2167 VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR CIter;
2168 const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry;
2169
2170 if (msTS - m_msDockUpdateTS > 200)
2171 {
2172 m_msDockUpdateTS = msTS;
2173#if 0
2174 /* todo: check this for optimization */
2175 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, myTextureName);
2176 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_STORAGE_HINT_APPLE,
2177 GL_STORAGE_SHARED_APPLE);
2178 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2179 glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA,
2180 sizex, sizey, 0, GL_BGRA,
2181 GL_UNSIGNED_INT_8_8_8_8_REV, myImagePtr);
2182 glCopyTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB,
2183 0, 0, 0, 0, 0, image_width, image_height);
2184 glFlush();
2185 /* Do other work processing here, using a double or triple buffer */
2186 glGetTexImage(GL_TEXTURE_RECTANGLE_ARB, 0, GL_BGRA,
2187 GL_UNSIGNED_INT_8_8_8_8_REV, pixels);
2188#endif
2189 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
2190 glDrawBuffer(GL_BACK);
2191
2192 /* Clear background to transparent */
2193 glClear(GL_COLOR_BUFFER_BIT);
2194
2195 rr = [m_DockTileView frame];
2196
2197 CrVrScrCompositorGetStretching(pCompositor, &xStretch, &yStretch);
2198
2199 CrVrScrCompositorConstIterInit(pCompositor, &CIter);
2200 while ((pEntry = CrVrScrCompositorConstIterNext(&CIter)) != NULL)
2201 {
2202 uint32_t cRegions;
2203 PCRTRECT paSrcRegions;
2204 PCRTRECT paDstRegions;
2205 int rc = CrVrScrCompositorEntryRegionsGet(pCompositor, pEntry, &cRegions, &paSrcRegions, &paDstRegions, NULL);
2206 uint32_t fFlags = CrVrScrCompositorEntryFlagsCombinedGet(pCompositor, pEntry);
2207 if (RT_SUCCESS(rc))
2208 {
2209 int rc = CrBltEnter(m_pBlitter);
2210 if (RT_SUCCESS(rc))
2211 {
2212 uint32_t i;
2213 for (i = 0; i < cRegions; ++i)
2214 {
2215 const CR_TEXDATA *pTexData;
2216 PCRTRECT pSrcRect = &paSrcRegions[i];
2217 PCRTRECT pDstRect = &paDstRegions[i];
2218 RTRECT DstRect, RestrictDstRect;
2219 RTRECT SrcRect, RestrictSrcRect;
2220
2221 vboxNSRectToRect(&m_RootRect, &RestrictDstRect);
2222 VBoxRectIntersected(&RestrictDstRect, pDstRect, &DstRect);
2223
2224 VBoxRectTranslate(&DstRect, -RestrictDstRect.xLeft, -RestrictDstRect.yTop);
2225
2226 VBoxRectScale(&DstRect, m_FBOThumbScaleX, m_FBOThumbScaleY);
2227
2228 if (VBoxRectIsZero(&DstRect))
2229 continue;
2230
2231 vboxNSRectToRectUnstretched(&m_RootRect, &RestrictSrcRect, xStretch, yStretch);
2232 VBoxRectTranslate(&RestrictSrcRect,
2233 -CrVrScrCompositorEntryRectGet(pEntry)->xLeft,
2234 -CrVrScrCompositorEntryRectGet(pEntry)->yTop);
2235 VBoxRectIntersected(&RestrictSrcRect, pSrcRect, &SrcRect);
2236
2237 if (VBoxRectIsZero(&SrcRect))
2238 continue;
2239
2240 pSrcRect = &SrcRect;
2241 pDstRect = &DstRect;
2242
2243 pTexData = CrVrScrCompositorEntryTexGet(pEntry);
2244
2245 CrBltBlitTexMural(m_pBlitter, true, CrTdTexGet(pTexData), pSrcRect, pDstRect, 1, fFlags);
2246 }
2247 CrBltLeave(m_pBlitter);
2248 }
2249 else
2250 {
2251 DEBUG_WARN(("CrBltEnter failed rc %d", rc));
2252#ifndef DEBUG_VERBOSE
2253 AssertMsgFailed(("CrBltEnter failed rc %Rrc", rc));
2254#endif
2255 }
2256 }
2257 else
2258 {
2259 DEBUG_MSG_1(("BlitStretched: CrVrScrCompositorEntryRegionsGet failed rc %d\n", rc));
2260 AssertMsgFailed(("BlitStretched: CrVrScrCompositorEntryRegionsGet failed rc %Rrc\n", rc));
2261 }
2262 }
2263
2264 glFinish();
2265
2266 glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
2267 glReadBuffer(GL_BACK);
2268 /* Here the magic of reading the FBO content in our own buffer
2269 * happens. We have to lock this access, in the case the dock
2270 * is updated currently. */
2271 [m_DockTileView lock];
2272 glReadPixels(0, m_RootRect.size.height - rr.size.height, rr.size.width, rr.size.height,
2273 GL_BGRA,
2274 GL_UNSIGNED_INT_8_8_8_8,
2275 [[m_DockTileView thumbBitmap] bitmapData]);
2276 [m_DockTileView unlock];
2277
2278#ifdef VBOX_WITH_CRDUMPER_THUMBNAIL
2279 ++g_cVBoxTgaCtr;
2280 crDumpNamedTGAF((GLint)rr.size.width, (GLint)rr.size.height,
2281 [[m_DockTileView thumbBitmap] bitmapData], "/Users/leo/vboxdumps/dump%d.tga", g_cVBoxTgaCtr);
2282#endif
2283
2284 pDT = [[NSApplication sharedApplication] dockTile];
2285
2286 /* Send a display message to the dock tile in the main thread */
2287 [[[NSApplication sharedApplication] dockTile] performSelectorOnMainThread:@selector(display) withObject:nil
2288 waitUntilDone:NO];
2289 }
2290 }
2291}
2292
2293- (void)clearVisibleRegions
2294{
2295 DEBUG_FUNC_ENTER();
2296 if (m_paClipRects)
2297 {
2298 RTMemFree(m_paClipRects);
2299 m_paClipRects = NULL;
2300 }
2301 m_cClipRects = 0;
2302 DEBUG_FUNC_LEAVE();
2303}
2304
2305- (GLboolean)vboxNeedsEmptyPresent
2306{
2307 if (m_fDataVisible)
2308 {
2309 m_fCleanupNeeded = true;
2310 return GL_TRUE;
2311 }
2312
2313 return GL_FALSE;
2314}
2315
2316- (void)setVisibleRegions:(GLint)cRects paRects:(const GLint*)paRects
2317{
2318 DEBUG_FUNC_ENTER();
2319 GLint cOldRects = m_cClipRects;
2320
2321 DEBUG_MSG_1(("OVIW(%p): setVisibleRegions: cRects=%d\n", (void *)self, cRects));
2322
2323 [self clearVisibleRegions];
2324
2325 if (cRects > 0)
2326 {
2327#ifdef DEBUG_poetzsch
2328 int i = 0;
2329 for (i = 0; i < cRects; ++i)
2330 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]));
2331#endif
2332
2333 m_paClipRects = (GLint*)RTMemAlloc(sizeof(GLint) * 4 * cRects);
2334 m_cClipRects = cRects;
2335 memcpy(m_paClipRects, paRects, sizeof(GLint) * 4 * cRects);
2336 }
2337
2338 DEBUG_FUNC_LEAVE();
2339}
2340
2341- (NSView *)dockTileScreen
2342{
2343 DEBUG_FUNC_ENTER();
2344 NSView *contentView = [[[NSApplication sharedApplication] dockTile] contentView];
2345 NSView *screenContent = nil;
2346
2347 /*
2348 * First try the new variant which checks if this window is within the
2349 * screen which is previewed in the dock.
2350 */
2351 if ([contentView respondsToSelector:@selector(screenContentWithParentView:)])
2352 screenContent = [contentView performSelector:@selector(screenContentWithParentView:) withObject:(id)m_pParentView];
2353 /*
2354 * If it fails, fall back to the old variant (VBox...).
2355 */
2356 else if ([contentView respondsToSelector:@selector(screenContent)])
2357 screenContent = [contentView performSelector:@selector(screenContent)];
2358
2359 DEBUG_FUNC_LEAVE();
2360 return screenContent;
2361}
2362
2363- (void)reshapeDockTile
2364{
2365 DEBUG_FUNC_ENTER();
2366 NSRect newFrame = NSZeroRect;
2367
2368 NSView *pView = [self dockTileScreen];
2369 if (pView != nil)
2370 {
2371 NSRect dockFrame = [pView frame];
2372 /** @todo This is not correct, we should use framebuffer size here, while
2373 * parent view frame size may differ in case of scrolling. */
2374 NSRect parentFrame = [m_pParentView frame];
2375
2376 m_FBOThumbScaleX = (float)dockFrame.size.width / parentFrame.size.width;
2377 m_FBOThumbScaleY = (float)dockFrame.size.height / parentFrame.size.height;
2378 newFrame = NSMakeRect((int)(m_Pos.x * m_FBOThumbScaleX),
2379 (int)(dockFrame.size.height - (m_Pos.y + m_Size.height - m_yInvRootOffset) * m_FBOThumbScaleY),
2380 (int)(m_Size.width * m_FBOThumbScaleX),
2381 (int)(m_Size.height * m_FBOThumbScaleY));
2382 /*
2383 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));
2384 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));
2385 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);
2386 */
2387 [m_DockTileView setFrame: newFrame];
2388 }
2389 DEBUG_FUNC_LEAVE();
2390}
2391
2392@end /* @implementation OverlayView */
2393
2394
2395/********************************************************************************
2396*
2397* OpenGL context management
2398*
2399********************************************************************************/
2400void cocoaGLCtxCreate(NativeNSOpenGLContextRef *ppCtx, GLbitfield fVisParams, NativeNSOpenGLContextRef pSharedCtx)
2401{
2402 DEBUG_FUNC_ENTER();
2403 NSOpenGLPixelFormat *pFmt = nil;
2404
2405 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
2406
2407 NSOpenGLPixelFormatAttribute attribs[24] =
2408 {
2409 NSOpenGLPFAAccelerated,
2410 NSOpenGLPFAColorSize, (NSOpenGLPixelFormatAttribute)24
2411 };
2412
2413 int i = 3;
2414
2415 if (fVisParams & CR_ALPHA_BIT)
2416 {
2417 DEBUG_MSG(("CR_ALPHA_BIT requested\n"));
2418 attribs[i++] = NSOpenGLPFAAlphaSize;
2419 attribs[i++] = 8;
2420 }
2421 if (fVisParams & CR_DEPTH_BIT)
2422 {
2423 DEBUG_MSG(("CR_DEPTH_BIT requested\n"));
2424 attribs[i++] = NSOpenGLPFADepthSize;
2425 attribs[i++] = 24;
2426 }
2427 if (fVisParams & CR_STENCIL_BIT)
2428 {
2429 DEBUG_MSG(("CR_STENCIL_BIT requested\n"));
2430 attribs[i++] = NSOpenGLPFAStencilSize;
2431 attribs[i++] = 8;
2432 }
2433 if (fVisParams & CR_ACCUM_BIT)
2434 {
2435 DEBUG_MSG(("CR_ACCUM_BIT requested\n"));
2436 attribs[i++] = NSOpenGLPFAAccumSize;
2437 if (fVisParams & CR_ALPHA_BIT)
2438 attribs[i++] = 32;
2439 else
2440 attribs[i++] = 24;
2441 }
2442 if (fVisParams & CR_MULTISAMPLE_BIT)
2443 {
2444 DEBUG_MSG(("CR_MULTISAMPLE_BIT requested\n"));
2445 attribs[i++] = NSOpenGLPFASampleBuffers;
2446 attribs[i++] = 1;
2447 attribs[i++] = NSOpenGLPFASamples;
2448 attribs[i++] = 4;
2449 }
2450 if (fVisParams & CR_DOUBLE_BIT)
2451 {
2452 DEBUG_MSG(("CR_DOUBLE_BIT requested\n"));
2453 attribs[i++] = NSOpenGLPFADoubleBuffer;
2454 }
2455 if (fVisParams & CR_STEREO_BIT)
2456 {
2457 /* We don't support that.
2458 DEBUG_MSG(("CR_STEREO_BIT requested\n"));
2459 attribs[i++] = NSOpenGLPFAStereo;
2460 */
2461 }
2462
2463 if (VBoxOglIsOfflineRenderingAppropriate())
2464 {
2465 DEBUG_MSG(("Offline rendering is enabled\n"));
2466 attribs[i++] = NSOpenGLPFAAllowOfflineRenderers;
2467 }
2468
2469 /* Mark the end */
2470 attribs[i++] = 0;
2471
2472 /* Choose a pixel format */
2473 pFmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
2474
2475 if (pFmt)
2476 {
2477 *ppCtx = [[OverlayOpenGLContext alloc] initWithFormat:pFmt shareContext:pSharedCtx];
2478
2479 /* Enable multi threaded OpenGL engine */
2480 /*
2481 CGLContextObj cglCtx = [*ppCtx CGLContextObj];
2482 CGLError err = CGLEnable(cglCtx, kCGLCEMPEngine);
2483 if (err != kCGLNoError)
2484 printf ("Couldn't enable MT OpenGL engine!\n");
2485 */
2486
2487 DEBUG_MSG(("New context %X\n", (uint)*ppCtx));
2488 }
2489
2490 [pPool release];
2491
2492 DEBUG_FUNC_LEAVE();
2493}
2494
2495void cocoaGLCtxDestroy(NativeNSOpenGLContextRef pCtx)
2496{
2497 DEBUG_FUNC_ENTER();
2498 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
2499
2500 [pCtx release];
2501 /*[pCtx performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO];*/
2502
2503 [pPool release];
2504 DEBUG_FUNC_LEAVE();
2505}
2506
2507/********************************************************************************
2508*
2509* View management
2510*
2511********************************************************************************/
2512typedef struct CR_RCD_CREATEVIEW
2513{
2514 WindowInfo *pWinInfo;
2515 NSView *pParentView;
2516 GLbitfield fVisParams;
2517 /* out */
2518 OverlayView *pView;
2519} CR_RCD_CREATEVIEW;
2520
2521static OverlayView * vboxViewCreate(WindowInfo *pWinInfo, NativeNSViewRef pParentView)
2522{
2523 DEBUG_FUNC_ENTER();
2524 /* Create our worker view */
2525 OverlayView* pView = [[OverlayView alloc] initWithFrame:NSZeroRect thread:RTThreadSelf() parentView:pParentView winInfo:pWinInfo];
2526
2527 if (pView)
2528 {
2529 /* We need a real window as container for the view */
2530 [[OverlayWindow alloc] initWithParentView:pParentView overlayView:pView];
2531 /* Return the freshly created overlay view */
2532 DEBUG_FUNC_LEAVE();
2533 return pView;
2534 }
2535
2536 DEBUG_FUNC_LEAVE();
2537 return NULL;
2538}
2539
2540static DECLCALLBACK(void) vboxRcdCreateView(void *pvCb)
2541{
2542 DEBUG_FUNC_ENTER();
2543 CR_RCD_CREATEVIEW * pCreateView = (CR_RCD_CREATEVIEW*)pvCb;
2544 pCreateView->pView = vboxViewCreate(pCreateView->pWinInfo, pCreateView->pParentView);
2545 DEBUG_FUNC_LEAVE();
2546}
2547
2548void cocoaViewCreate(NativeNSViewRef *ppView, WindowInfo *pWinInfo, NativeNSViewRef pParentView, GLbitfield fVisParams)
2549{
2550 DEBUG_FUNC_ENTER();
2551 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
2552
2553 VBoxMainThreadTaskRunner *pRunner = [VBoxMainThreadTaskRunner globalInstance];
2554 /* make sure all tasks are run, to preserve the order */
2555 [pRunner runTasksSyncIfPossible];
2556
2557 renderspuWinRetain(pWinInfo);
2558
2559 if (renderspuCalloutAvailable())
2560 {
2561 CR_RCD_CREATEVIEW CreateView;
2562 CreateView.pWinInfo = pWinInfo;
2563 CreateView.pParentView = pParentView;
2564 CreateView.fVisParams = fVisParams;
2565 CreateView.pView = NULL;
2566 renderspuCalloutClient(vboxRcdCreateView, &CreateView);
2567 *ppView = CreateView.pView;
2568 }
2569 else
2570 {
2571 DEBUG_MSG(("no callout available on createWindow\n"));
2572#if 0
2573 dispatch_sync(dispatch_get_main_queue(), ^{
2574#endif
2575 *ppView = vboxViewCreate(pWinInfo, pParentView);
2576#if 0
2577 });
2578#endif
2579 }
2580
2581 if (!*ppView)
2582 renderspuWinRelease(pWinInfo);
2583
2584 [pPool release];
2585
2586 DEBUG_FUNC_LEAVE();
2587}
2588
2589void cocoaViewReparent(NativeNSViewRef pView, NativeNSViewRef pParentView)
2590{
2591 DEBUG_FUNC_ENTER();
2592 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
2593
2594 OverlayView* pOView = (OverlayView*)pView;
2595
2596 if (pOView)
2597 {
2598 [pOView vboxReparent:pParentView];
2599 }
2600
2601 [pPool release];
2602
2603 DEBUG_FUNC_LEAVE();
2604}
2605
2606typedef struct CR_RCD_DESTROYVIEW
2607{
2608 OverlayView *pView;
2609} CR_RCD_DESTROYVIEW;
2610
2611static DECLCALLBACK(void) vboxRcdDestroyView(void *pvCb)
2612{
2613 DEBUG_FUNC_ENTER();
2614 CR_RCD_DESTROYVIEW * pDestroyView = (CR_RCD_DESTROYVIEW*)pvCb;
2615 [pDestroyView->pView vboxDestroy];
2616 DEBUG_FUNC_LEAVE();
2617}
2618
2619void cocoaViewDestroy(NativeNSViewRef pView)
2620{
2621 DEBUG_FUNC_ENTER();
2622 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
2623
2624 VBoxMainThreadTaskRunner *pRunner = [VBoxMainThreadTaskRunner globalInstance];
2625 [pRunner addObj:pView selector:@selector(vboxDestroy) arg:nil];
2626
2627 [pPool release];
2628
2629 DEBUG_FUNC_LEAVE();
2630}
2631
2632void cocoaViewShow(NativeNSViewRef pView, GLboolean fShowIt)
2633{
2634 DEBUG_FUNC_ENTER();
2635 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
2636
2637 [(OverlayView*)pView vboxSetVisible:fShowIt];
2638
2639 [pPool release];
2640 DEBUG_FUNC_LEAVE();
2641}
2642
2643void cocoaViewDisplay(NativeNSViewRef pView)
2644{
2645 DEBUG_FUNC_ENTER();
2646 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
2647
2648 DEBUG_WARN(("cocoaViewDisplay should never happen!\n"));
2649 DEBUG_MSG_1(("cocoaViewDisplay %p\n", (void *)pView));
2650 [(OverlayView*)pView swapFBO];
2651
2652 [pPool release];
2653
2654 DEBUG_FUNC_LEAVE();
2655}
2656
2657void cocoaViewSetPosition(NativeNSViewRef pView, NativeNSViewRef pParentView, int x, int y)
2658{
2659 DEBUG_FUNC_ENTER();
2660 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
2661
2662 [(OverlayView*)pView vboxSetPos:NSMakePoint(x, y)];
2663
2664 [pPool release];
2665
2666 DEBUG_FUNC_LEAVE();
2667}
2668
2669void cocoaViewSetSize(NativeNSViewRef pView, int w, int h)
2670{
2671 DEBUG_FUNC_ENTER();
2672 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
2673
2674 [(OverlayView*)pView vboxSetSize:NSMakeSize(w, h)];
2675
2676 [pPool release];
2677
2678 DEBUG_FUNC_LEAVE();
2679}
2680
2681typedef struct CR_RCD_GETGEOMETRY
2682{
2683 OverlayView *pView;
2684 NSRect rect;
2685} CR_RCD_GETGEOMETRY;
2686
2687static DECLCALLBACK(void) vboxRcdGetGeomerty(void *pvUser)
2688{
2689 DEBUG_FUNC_ENTER();
2690 CR_RCD_GETGEOMETRY * pGetGeometry = (CR_RCD_GETGEOMETRY *)pvUser;
2691 pGetGeometry->rect = [[pGetGeometry->pView window] frame];
2692 DEBUG_FUNC_LEAVE();
2693}
2694
2695void cocoaViewGetGeometry(NativeNSViewRef pView, int *pX, int *pY, int *pW, int *pH)
2696{
2697 NSAutoreleasePool *pPool;
2698 DEBUG_FUNC_ENTER();
2699 pPool = [[NSAutoreleasePool alloc] init];
2700
2701 NSRect frame;
2702 VBoxMainThreadTaskRunner *pRunner = [VBoxMainThreadTaskRunner globalInstance];
2703 /* make sure all tasks are run, to preserve the order */
2704 [pRunner runTasksSyncIfPossible];
2705
2706
2707 if (renderspuCalloutAvailable())
2708 {
2709 CR_RCD_GETGEOMETRY GetGeometry;
2710 GetGeometry.pView = (OverlayView *)pView;
2711 renderspuCalloutClient(vboxRcdGetGeomerty, &GetGeometry);
2712 frame = GetGeometry.rect;
2713 }
2714 else
2715 {
2716 DEBUG_MSG(("no callout available on getGeometry\n"));
2717 frame = [[pView window] frame];
2718 }
2719
2720 *pX = frame.origin.x;
2721 *pY = frame.origin.y;
2722 *pW = frame.size.width;
2723 *pH = frame.size.height;
2724
2725 [pPool release];
2726
2727 DEBUG_FUNC_LEAVE();
2728}
2729
2730void cocoaViewPresentComposition(NativeNSViewRef pView, const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pChangedEntry)
2731{
2732 DEBUG_FUNC_ENTER();
2733 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
2734 NSOpenGLContext *pCtx;
2735
2736 /* view should not necesserily have a context set */
2737 pCtx = [(OverlayView*)pView glCtx];
2738 if (!pCtx)
2739 {
2740 ContextInfo * pCtxInfo = renderspuDefaultSharedContextAcquire();
2741 if (!pCtxInfo)
2742 {
2743 DEBUG_WARN(("renderspuDefaultSharedContextAcquire returned NULL"));
2744
2745 [pPool release];
2746 DEBUG_FUNC_LEAVE();
2747 return;
2748 }
2749
2750 pCtx = pCtxInfo->context;
2751
2752 [(OverlayView*)pView setGLCtx:pCtx];
2753 }
2754
2755 [(OverlayView*)pView presentComposition:pChangedEntry];
2756
2757 [pPool release];
2758
2759 DEBUG_FUNC_LEAVE();
2760}
2761
2762void cocoaViewMakeCurrentContext(NativeNSViewRef pView, NativeNSOpenGLContextRef pCtx)
2763{
2764 DEBUG_FUNC_ENTER();
2765 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
2766
2767 DEBUG_MSG(("cocoaViewMakeCurrentContext(%p, %p)\n", (void *)pView, (void *)pCtx));
2768
2769 if (pView)
2770 {
2771 [(OverlayView*)pView setGLCtx:pCtx];
2772 [(OverlayView*)pView makeCurrentFBO];
2773 }
2774 else
2775 {
2776 [NSOpenGLContext clearCurrentContext];
2777 }
2778
2779 [pPool release];
2780
2781 DEBUG_FUNC_LEAVE();
2782}
2783
2784GLboolean cocoaViewNeedsEmptyPresent(NativeNSViewRef pView)
2785{
2786 DEBUG_FUNC_ENTER();
2787
2788 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
2789
2790 GLboolean fNeedsPresent = [(OverlayView*)pView vboxNeedsEmptyPresent];
2791
2792 [pPool release];
2793
2794 DEBUG_FUNC_LEAVE();
2795
2796 return fNeedsPresent;
2797}
2798
2799void cocoaViewSetVisibleRegion(NativeNSViewRef pView, GLint cRects, const GLint* paRects)
2800{
2801 DEBUG_FUNC_ENTER();
2802 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
2803
2804 [(OverlayView*)pView setVisibleRegions:cRects paRects:paRects];
2805
2806 [pPool release];
2807
2808 DEBUG_FUNC_LEAVE();
2809}
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