VirtualBox

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

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

Mac OS X host 3D: preparation for output unscaled content to HiDPI monitor.

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