VirtualBox

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

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

Host 3D unscaled HiDPI output: privide notifyHiDPIOutputPolicyChange() IDisplay interface to GUI in ouder to notify 3D about corresponding user option value change.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 100.4 KB
Line 
1/* $Id: renderspu_cocoa_helper.m 54582 2015-03-02 15:42:16Z 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#if defined(VBOX_WITH_CONFIGURABLE_HIDPI_SCALING) && !defined(IN_VMSVGA3D)
1432 crDebug("HiDPI: up-scaling is %s on NSView init.", render_spu.fUnscaledHiDPI ? "OFF" : "ON");
1433 if (render_spu.fUnscaledHiDPI)
1434 [self performSelector:@selector(setWantsBestResolutionOpenGLSurface:) withObject: (id)YES];
1435#endif
1436
1437 COCOA_LOG_FLOW(("%s: returns self=%p\n", __PRETTY_FUNCTION__, (void *)self));
1438 return self;
1439}
1440
1441- (void)cleanupData
1442{
1443 COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
1444
1445 [self deleteDockTile];
1446
1447 [self setGLCtx:nil];
1448
1449 if (m_pSharedGLCtx)
1450 {
1451 if ([m_pSharedGLCtx view] == self)
1452 [m_pSharedGLCtx clearDrawable];
1453
1454 [m_pSharedGLCtx release];
1455 m_pSharedGLCtx = nil;
1456
1457 CrBltTerm(m_pBlitter);
1458 RTMemFree(m_pBlitter);
1459 m_pBlitter = nil;
1460 }
1461
1462 [self clearVisibleRegions];
1463
1464 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
1465}
1466
1467- (void)dealloc
1468{
1469 COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
1470
1471 [self cleanupData];
1472 [super dealloc];
1473
1474 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
1475}
1476
1477- (void)drawRect:(NSRect)aRect
1478{
1479 COCOA_LOG_FLOW(("%s: self=%p aRect=%d,%d %d,%d\n", __PRETTY_FUNCTION__, (void *)self, (int)aRect.origin.x, (int)aRect.origin.y,
1480 (int)aRect.size.width, (int)aRect.size.height));
1481
1482 [self vboxTryDrawUI];
1483
1484 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
1485}
1486
1487- (void)setGLCtx:(NSOpenGLContext *)pCtx
1488{
1489 COCOA_LOG_FLOW(("%s: self=%p pCtx=%p (old=%p)\n", __PRETTY_FUNCTION__, (void *)self, (void *)pCtx, m_pGLCtx));
1490
1491 /*
1492 * Only do something if the context changes.
1493 */
1494 if (m_pGLCtx != pCtx)
1495 {
1496 /* Ensure the context drawable is cleared to avoid holding a reference to inexistent view. */
1497 if (m_pGLCtx)
1498 {
1499 [m_pGLCtx clearDrawable];
1500 [m_pGLCtx release];
1501 /*[m_pGLCtx performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO];*/
1502 }
1503
1504 m_pGLCtx = pCtx;
1505 if (pCtx)
1506 [pCtx retain];
1507 }
1508
1509 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
1510}
1511
1512- (NSOpenGLContext *)glCtx
1513{
1514 COCOA_LOG_FLOW(("%s: self=%p returns %p\n", __PRETTY_FUNCTION__, (void *)self, (void *)m_pGLCtx));
1515 return m_pGLCtx;
1516}
1517
1518- (NSView *)parentView
1519{
1520 COCOA_LOG_FLOW(("%s: self=%p returns %p\n", __PRETTY_FUNCTION__, (void *)self, (void *)m_pParentView));
1521 return m_pParentView;
1522}
1523
1524- (void)setParentView:(NSView *)pView
1525{
1526 COCOA_LOG_FLOW(("%s: self=%p pView=%p (old=%p)\n", __PRETTY_FUNCTION__, (void *)self, (void *)pView, m_pParentView));
1527
1528 m_pParentView = pView;
1529
1530 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
1531}
1532
1533- (void)setOverlayWin:(NSWindow *)pWin
1534{
1535 COCOA_LOG_FLOW(("%s: self=%p pWin=%p (old=%p)\n", __PRETTY_FUNCTION__, (void *)self, (void *)pWin, m_pOverlayWin));
1536
1537 m_pOverlayWin = pWin;
1538
1539 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
1540}
1541
1542- (NSWindow *)overlayWin
1543{
1544 COCOA_LOG_FLOW(("%s: self=%p returns %p\n", __PRETTY_FUNCTION__, (void *)self, (void *)m_pOverlayWin));
1545 return m_pOverlayWin;
1546}
1547
1548- (void)vboxSetPosUI:(NSPoint)pos
1549{
1550 COCOA_LOG_FLOW(("%s: self=%p pos=%d,%d (old pos=%d,%d)\n", __PRETTY_FUNCTION__, (void *)self, (int)pos.x, (int)pos.y,
1551 (int)m_Pos.x, (int)m_Pos.y));
1552
1553 DEBUG_MSG(("vboxSetPosUI: [%d, %d].\n", (int)pos.x, (int)pos.y));
1554
1555 m_Pos = pos;
1556
1557 if (m_fEverSized)
1558 [self vboxReshapePerform];
1559
1560 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
1561}
1562
1563- (void)vboxSetPosUIObj:(NSValue *)pPos
1564{
1565 COCOA_LOG_FLOW(("%s: self=%p pPos=%p (%d,%d) (old pos=%d,%d)\n", __PRETTY_FUNCTION__, (void *)self, pPos,
1566 (int)[pPos pointValue].x, (int)[pPos pointValue].y, (int)m_Pos.x, (int)m_Pos.y));
1567
1568 NSPoint pos = [pPos pointValue];
1569 [self vboxSetPosUI:pos];
1570
1571 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
1572}
1573
1574- (void)vboxSetPos:(NSPoint)pos
1575{
1576 COCOA_LOG_FLOW(("%s: self=%p pos=%d,%d (old pos=%d,%d)\n", __PRETTY_FUNCTION__, (void *)self, (int)pos.x, (int)pos.y,
1577 (int)m_Pos.x, (int)m_Pos.y));
1578
1579 VBoxMainThreadTaskRunner *pRunner = [VBoxMainThreadTaskRunner globalInstance];
1580 NSValue *pPos = [NSValue valueWithPoint:pos];
1581 [pRunner addObj:self selector:@selector(vboxSetPosUIObj:) arg:pPos];
1582
1583 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
1584}
1585
1586- (NSPoint)pos
1587{
1588 COCOA_LOG_FLOW(("%s: self=%p returns %d,%d\n", __PRETTY_FUNCTION__, (void *)self, (int)m_Pos.x, (int)m_Pos.y));
1589 return m_Pos;
1590}
1591
1592- (bool)isEverSized
1593{
1594 COCOA_LOG_FLOW(("%s: self=%p returns %d\n", __PRETTY_FUNCTION__, (void *)self, m_fEverSized));
1595 return m_fEverSized;
1596}
1597
1598- (void)vboxDestroy
1599{
1600 COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
1601 BOOL fIsMain = [NSThread isMainThread];
1602 NSWindow *pWin = nil;
1603
1604 Assert(fIsMain);
1605
1606 /* Hide the view early. */
1607 [self setHidden: YES];
1608
1609 pWin = [self window];
1610 [[NSNotificationCenter defaultCenter] removeObserver:pWin];
1611 [pWin setContentView: nil];
1612 [[pWin parentWindow] removeChildWindow: pWin];
1613
1614 if (fIsMain)
1615 [pWin release];
1616 else
1617 {
1618 /* We can NOT run synchronously with the main thread since this may lead to a deadlock,
1619 caused by main thread waiting xpcom thread, xpcom thread waiting to main hgcm thread,
1620 and main hgcm thread waiting for us, this is why use waitUntilDone:NO,
1621 which should cause no harm. */
1622 [pWin performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO];
1623 }
1624
1625 [self cleanupData];
1626
1627 if (fIsMain)
1628 [self release];
1629 else
1630 {
1631 /* We can NOT run synchronously with the main thread since this may lead to a deadlock,
1632 caused by main thread waiting xpcom thread, xpcom thread waiting to main hgcm thread,
1633 and main hgcm thread waiting for us, this is why use waitUntilDone:NO.
1634 We need to avoid concurrency though, so we cleanup some data right away via a cleanupData call. */
1635 [self performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO];
1636 }
1637
1638 renderspuWinRelease(m_pWinInfo);
1639
1640 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
1641}
1642
1643- (void)vboxSetSizeUIObj:(NSValue *)pSize
1644{
1645 COCOA_LOG_FLOW(("%s: self=%p pSize=%p (%d,%d)\n", __PRETTY_FUNCTION__, (void *)self, (void *)pSize,
1646 (int)[pSize sizeValue].width, (int)[pSize sizeValue].height));
1647
1648 NSSize size = [pSize sizeValue];
1649 [self vboxSetSizeUI:size];
1650
1651 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
1652}
1653
1654- (void)vboxSetSizeUI:(NSSize)size
1655{
1656 COCOA_LOG_FLOW(("%s: self=%p size=%d,%d\n", __PRETTY_FUNCTION__, (void *)self, (int)size.width, (int)size.height));
1657
1658 m_Size = size;
1659 m_fEverSized = true;
1660
1661 DEBUG_MSG(("OVIW(%p): vboxSetSize: new size: %dx%d\n", (void *)self, (int)m_Size.width, (int)m_Size.height));
1662 [self vboxReshapeOnResizePerform];
1663
1664 /* ensure window contents is updated after that */
1665 [self vboxTryDrawUI];
1666
1667 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
1668}
1669
1670- (void)vboxSetSize:(NSSize)size
1671{
1672 COCOA_LOG_FLOW(("%s: self=%p size=%d,%d\n", __PRETTY_FUNCTION__, (void *)self, (int)size.width, (int)size.height));
1673
1674 VBoxMainThreadTaskRunner *pRunner = [VBoxMainThreadTaskRunner globalInstance];
1675 NSValue *pSize = [NSValue valueWithSize:size];
1676 [pRunner addObj:self selector:@selector(vboxSetSizeUIObj:) arg:pSize];
1677
1678 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
1679}
1680
1681- (NSSize)size
1682{
1683 COCOA_LOG_FLOW(("%s: self=%p returns %d,%d\n", __PRETTY_FUNCTION__, (void *)self, (int)m_Size.width, (int)m_Size.height));
1684 return m_Size;
1685}
1686
1687- (void)updateViewportCS
1688{
1689 COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
1690
1691 /* Update the viewport for our OpenGL view. */
1692 [m_pSharedGLCtx update];
1693
1694 [self vboxBlitterSyncWindow];
1695
1696 /* Clear background to transparent. */
1697 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
1698
1699 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
1700}
1701
1702- (void)vboxReshapeOnResizePerform
1703{
1704 COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
1705
1706 [self vboxReshapePerform];
1707 [self createDockTile];
1708
1709 /* have to rebind GL_TEXTURE_RECTANGLE_ARB as m_FBOTexId could be changed in updateFBO call */
1710 m_fNeedViewportUpdate = true;
1711#if 0
1712 pCurCtx = [NSOpenGLContext currentContext];
1713 if (pCurCtx && pCurCtx == m_pGLCtx && (pCurView = [pCurCtx view]) == self)
1714 {
1715 [m_pGLCtx update];
1716 m_fNeedCtxUpdate = false;
1717 }
1718 else
1719 {
1720 /* do it in a lazy way */
1721 m_fNeedCtxUpdate = true;
1722 }
1723#endif
1724
1725 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
1726}
1727
1728- (void)vboxReshapeOnReparentPerform
1729{
1730 COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
1731 [self vboxReshapePerform];
1732 [self createDockTile];
1733 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
1734}
1735
1736#ifdef VBOX_WITH_CONFIGURABLE_HIDPI_SCALING
1737- (NSRect)safeConvertRectToBacking:(NSRect *)pRect
1738{
1739 NSRect resultingRect = NSZeroRect;
1740
1741 NSWindow *pWindow = [m_pParentView window];
1742 if (pWindow)
1743 {
1744 if ([pWindow respondsToSelector:@selector(convertRectToBacking:)])
1745 {
1746 NSMethodSignature *pSignature = [pWindow methodSignatureForSelector:@selector(convertRectToBacking:)];
1747 if (pSignature)
1748 {
1749 NSInvocation *pInvocation = [NSInvocation invocationWithMethodSignature:pSignature];
1750 if (pInvocation)
1751 {
1752 [pInvocation setSelector:@selector(convertRectToBacking:)];
1753 [pInvocation setTarget:pWindow];
1754 [pInvocation setArgument:pRect atIndex:2];
1755 [pInvocation invoke];
1756 [pInvocation getReturnValue:&resultingRect];
1757
1758 DEBUG_MSG(("safeConvertRectToBacking: convert [X, Y, WxH]: [%d, %d, %dx%d] -> [%d, %d, %dx%d]\n",
1759 (int)pRect ->origin.x, (int)pRect ->origin.y, (int)pRect ->size.width, (int)pRect ->size.width,
1760 (int)resultingRect.origin.x, (int)resultingRect.origin.y, (int)resultingRect.size.width, (int)resultingRect.size.width));
1761
1762 return resultingRect;
1763 }
1764 }
1765 }
1766 }
1767 else
1768 /* Should never happen. */
1769 DEBUG_WARN(("safeConvertRectToBacking: parent widget has no window.\n"));
1770
1771 resultingRect = *pRect;
1772
1773 DEBUG_MSG(("safeConvertRectToBacking (reurn as is): convert [X, Y, WxH]: [%d, %d, %dx%d] -> [%d, %d, %dx%d]\n",
1774 (int)pRect ->origin.x, (int)pRect ->origin.y, (int)pRect ->size.width, (int)pRect ->size.width,
1775 (int)resultingRect.origin.x, (int)resultingRect.origin.y, (int)resultingRect.size.width, (int)resultingRect.size.width));
1776
1777 return resultingRect;
1778}
1779
1780
1781- (CGFloat)safeGetBackingScaleFactor
1782{
1783 /* Assume its default value. */
1784 CGFloat backingScaleFactor = 1.;
1785
1786 NSWindow *pWindow = [m_pParentView window];
1787 if (pWindow)
1788 {
1789 NSScreen *pScreen = [pWindow screen];
1790 if (pScreen)
1791 {
1792 if ([pScreen respondsToSelector:@selector(backingScaleFactor)])
1793 {
1794 NSMethodSignature *pSignature = [pScreen methodSignatureForSelector:@selector(backingScaleFactor)];
1795 if (pSignature)
1796 {
1797 NSInvocation *pInvocation = [NSInvocation invocationWithMethodSignature:pSignature];
1798 if (pInvocation)
1799 {
1800 [pInvocation setSelector:@selector(backingScaleFactor)];
1801 [pInvocation setTarget:pScreen];
1802 [pInvocation invoke];
1803 [pInvocation getReturnValue:&backingScaleFactor];
1804
1805 DEBUG_MSG(("safeGetBackingScaleFactor: %d\n", (int)backingScaleFactor));
1806
1807 return backingScaleFactor;
1808 }
1809 else
1810 DEBUG_WARN(("safeGetBackingScaleFactor: unable to create invocation for backingScaleFactor method signature.\n"));
1811 }
1812 else
1813 DEBUG_WARN(("safeGetBackingScaleFactor: unable to create method signature for backingScaleFactor selector.\n"));
1814 }
1815 else
1816 DEBUG_WARN(("safeGetBackingScaleFactor: NSScreen does not respond to backingScaleFactor selector.\n"));
1817 }
1818 else
1819 /* Should never happen. */
1820 DEBUG_WARN(("safeGetBackingScaleFactor: parent window has no screen.\n"));
1821 }
1822 else
1823 /* Should never happen. */
1824 DEBUG_WARN(("safeGetBackingScaleFactor: parent widget has no window.\n"));
1825
1826 return backingScaleFactor;
1827}
1828
1829#endif
1830
1831
1832- (NSRect)safeConvertToScreen:(NSRect *)pRect
1833{
1834 NSRect resultingRect = NSZeroRect;
1835
1836 NSWindow *pWindow = [m_pParentView window];
1837 if (pWindow)
1838 {
1839 if ([pWindow respondsToSelector:@selector(convertRectToScreen:)])
1840 {
1841 NSMethodSignature *pSignature = [pWindow methodSignatureForSelector:@selector(convertRectToScreen:)];
1842 if (pSignature)
1843 {
1844 NSInvocation *pInvocation = [NSInvocation invocationWithMethodSignature:pSignature];
1845 if (pInvocation)
1846 {
1847 [pInvocation setSelector:@selector(convertRectToScreen:)];
1848 [pInvocation setTarget:pWindow];
1849 [pInvocation setArgument:pRect atIndex:2];
1850 [pInvocation invoke];
1851 [pInvocation getReturnValue:&resultingRect];
1852
1853 DEBUG_MSG(("safeConvertToScreen: convert [X, Y, WxH]: [%d, %d, %dx%d] -> [%d, %d, %dx%d]\n",
1854 (int)pRect ->origin.x, (int)pRect ->origin.y, (int)pRect ->size.width, (int)pRect ->size.width,
1855 (int)resultingRect.origin.x, (int)resultingRect.origin.y, (int)resultingRect.size.width, (int)resultingRect.size.width));
1856
1857 return resultingRect;
1858 }
1859 }
1860 }
1861
1862 /* If we failed, let's use deprecated @selector(convertBaseToScreen:). It is a bit hacky,
1863 * but what to do if we stick to SDK 10.6. */
1864 resultingRect.origin = [[m_pParentView window] convertBaseToScreen:pRect->origin];
1865 resultingRect.size = pRect->size;
1866 }
1867 else
1868 /* Should never happen. */
1869 DEBUG_WARN(("safeConvertToScreen: parent widget has no window.\n"));
1870
1871 DEBUG_MSG(("safeConvertToScreen (deprecated method): convert [X, Y, WxH]: [%d, %d, %dx%d] -> [%d, %d, %dx%d]\n",
1872 (int)pRect ->origin.x, (int)pRect ->origin.y, (int)pRect ->size.width, (int)pRect ->size.width,
1873 (int)resultingRect.origin.x, (int)resultingRect.origin.y, (int)resultingRect.size.width, (int)resultingRect.size.width));
1874
1875 return resultingRect;
1876}
1877
1878- (void)vboxReshapePerform
1879{
1880 COCOA_LOG_FLOW(("%s: self=%p - m_DockTileView=%p\n", __PRETTY_FUNCTION__, (void *)self, (void *)m_DockTileView));
1881
1882 /* NOTE: Please consider the next naming convention for variables.
1883 *
1884 * Rectangle variables:
1885 *
1886 * <object to represent><coordinate system>:
1887 * <object to represent>:
1888 * parentFrame - a frame of the parent container (NSView) object
1889 * childFrame - a frame required to display guest content
1890 * windowFrame - resulting window frame constructed as an intersection of parentFrame and childFrame
1891 * <coordinate system>:
1892 * VCS - View Coordinate System
1893 * WCS - Window Coordinate System
1894 * SCS - Screen Coordinate System
1895 *
1896 * The same convention applied to offset variables naming as well which are of format:
1897 *
1898 * <object to represent><coordinate><coordinate system>.
1899 *
1900 * https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CocoaDrawingGuide/Transforms/Transforms.html
1901 */
1902
1903 NSRect parentFrameVCS, parentFrameWCS, parentFrameSCS;
1904 NSRect childFrameWCS, childFrameSCS;
1905 NSRect windowFrameSCS;
1906
1907 CGFloat childFrameXWCS, childFrameYWCS;
1908
1909 /* We need to construct a new window frame (windowFrameSCS) for entire NSWindow object in
1910 * screen coordinates. In order to make 3D overlay window to do not overlap Cocoa and Qt GUI elements (titlebar,
1911 * Qt statusbar, scroll bars etc) let's do the next. Get parent view visible area (parentFrameSCS) in (NS)Screen
1912 * coordinates. Then get the area required to diaplay guest content (childFrameSCS) in (NS)Screen coordinates as well.
1913 * The intersection of these two areas in screen coordinates will be a new frame for entire NSWindow object. */
1914
1915 parentFrameVCS = [m_pParentView frame];
1916 parentFrameWCS = [m_pParentView convertRect:parentFrameVCS toView:nil];
1917 parentFrameSCS = [self safeConvertToScreen:&parentFrameWCS];
1918
1919 /* Choose childFrame origin in a bit special way. Its pop-left corner should stick to its parent top-left corner. */
1920 childFrameXWCS = parentFrameWCS.origin.x + m_Pos.x;
1921 childFrameYWCS = parentFrameWCS.origin.y - m_Pos.y - (m_Size.height - parentFrameWCS.size.height);
1922 childFrameWCS = NSMakeRect(childFrameXWCS, childFrameYWCS, m_Size.width, m_Size.height);
1923 childFrameSCS = [self safeConvertToScreen:&childFrameWCS];
1924
1925 windowFrameSCS = NSIntersectionRect(parentFrameSCS, childFrameSCS);
1926
1927 DEBUG_MSG(("vboxReshapePerform: a new overlay frame [%d, %d, %dx%d] has been constructed from intersection of window frame "
1928 "[%d, %d, %dx%d] and guest content rectangle [%d, %d, %dx%d]; m_Pos=[%d, %d], m_Size=%dx%d.\n",
1929 (int)windowFrameSCS.origin.x, (int)windowFrameSCS.origin.y, (int)windowFrameSCS.size.width, (int)windowFrameSCS.size.width,
1930 (int)parentFrameSCS.origin.x, (int)parentFrameSCS.origin.y, (int)parentFrameSCS.size.width, (int)parentFrameSCS.size.width,
1931 (int)childFrameSCS .origin.x, (int)childFrameSCS .origin.y, (int)childFrameSCS .size.width, (int)childFrameSCS .size.width,
1932 (int)m_Pos.x, (int)m_Pos.y, (int)m_Size.width, (int)m_Size.height));
1933
1934 /* @todo galitsyn: drop this!
1935 * Later we have to correct the texture position in the case the window is
1936 * out of the parents window frame. So save the shift values for later use. */
1937 m_RootRect.origin.x = windowFrameSCS.origin.x - childFrameSCS.origin.x;
1938 m_RootRect.origin.y = childFrameSCS.size.height + childFrameSCS.origin.y - (windowFrameSCS.size.height + windowFrameSCS.origin.y);
1939 m_RootRect.size = windowFrameSCS.size;
1940 m_yInvRootOffset = windowFrameSCS.origin.y - childFrameSCS.origin.y;
1941
1942 DEBUG_MSG(("vboxReshapePerform: [%#p]: m_RootRect pos[%d : %d] size[%d : %d]\n",
1943 (void *)self, (int)m_RootRect.origin.x, (int)m_RootRect.origin.y, (int)m_RootRect.size.width, (int)m_RootRect.size.height));
1944
1945 /* Set the new frame. */
1946 [[self window] setFrame:windowFrameSCS display:YES];
1947
1948 /* Inform the dock tile view as well. */
1949 [self reshapeDockTile];
1950
1951 /* Make sure the context is updated accordingly. */
1952 /* [self updateViewport]; */
1953 if (m_pSharedGLCtx)
1954 {
1955 VBOX_CR_RENDER_CTX_INFO CtxInfo;
1956 vboxCtxEnter(m_pSharedGLCtx, &CtxInfo);
1957
1958 [self updateViewportCS];
1959
1960 vboxCtxLeave(&CtxInfo);
1961 }
1962
1963 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
1964}
1965
1966- (void)createDockTile
1967{
1968 COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
1969 NSView *pDockScreen = nil;
1970
1971 [self deleteDockTile];
1972
1973 /* Is there a dock tile preview enabled in the GUI? If so setup a
1974 * additional thumbnail view for the dock tile. */
1975 pDockScreen = [self dockTileScreen];
1976 if (pDockScreen)
1977 {
1978 m_DockTileView = [[DockOverlayView alloc] init];
1979 [self reshapeDockTile];
1980 [pDockScreen addSubview:m_DockTileView];
1981 }
1982
1983 COCOA_LOG_FLOW(("%s: returns - m_DockTileView\n", __PRETTY_FUNCTION__, (void *)m_DockTileView));
1984}
1985
1986- (void)deleteDockTile
1987{
1988 COCOA_LOG_FLOW(("%s: self=%p - m_DockTileView=%p\n", __PRETTY_FUNCTION__, (void *)self, (void *)m_DockTileView));
1989
1990 if (m_DockTileView != nil)
1991 {
1992 [m_DockTileView removeFromSuperview];
1993 [m_DockTileView release];
1994 m_DockTileView = nil;
1995 }
1996
1997 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
1998}
1999
2000- (void)makeCurrentFBO
2001{
2002 COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
2003
2004 if (m_pGLCtx)
2005 {
2006 if ([m_pGLCtx view] != self)
2007 {
2008 /* We change the active view, so flush first */
2009 if ([NSOpenGLContext currentContext] != 0)
2010 glFlush();
2011 [m_pGLCtx setView: self];
2012 DEBUG_CHECK_GL_ERROR();
2013 }
2014
2015 /*
2016 if ([NSOpenGLContext currentContext] != m_pGLCtx)
2017 */
2018 {
2019 [m_pGLCtx makeCurrentContext];
2020 DEBUG_CHECK_GL_ERROR();
2021 if (m_fNeedCtxUpdate == true)
2022 {
2023 [m_pGLCtx update];
2024 m_fNeedCtxUpdate = false;
2025 }
2026 }
2027
2028 if (!m_FBOId)
2029 {
2030 glGenFramebuffersEXT(1, &m_FBOId);
2031 Assert(m_FBOId);
2032 }
2033 }
2034
2035 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
2036}
2037
2038- (bool)vboxSharedCtxCreate
2039{
2040 COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
2041
2042 if (m_pSharedGLCtx)
2043 {
2044 COCOA_LOG_FLOW(("%s: returns true (m_pSharedGLCtx=%p)\n", __PRETTY_FUNCTION__, (void *)m_pSharedGLCtx));
2045 return true;
2046 }
2047
2048 Assert(!m_pBlitter);
2049 m_pBlitter = RTMemAlloc(sizeof(*m_pBlitter));
2050 if (RT_UNLIKELY(!m_pBlitter))
2051 {
2052 DEBUG_WARN(("m_pBlitter allocation failed"));
2053 COCOA_LOG_FLOW(("%s: returns false - m_pBlitter allocation failed\n", __PRETTY_FUNCTION__));
2054 return false;
2055 }
2056
2057 int rc = CrBltInit(m_pBlitter, NULL, false /*fCreateNewCtx*/, false /*fForceDrawBlt*/,
2058#ifdef IN_VMSVGA3D
2059 NULL /** @todo */, NULL /** @todo */
2060#else
2061 &render_spu.GlobalShaders, &render_spu.blitterDispatch
2062#endif
2063 );
2064 if (RT_FAILURE(rc))
2065 {
2066 DEBUG_WARN(("CrBltInit failed, rc %d", rc));
2067 RTMemFree(m_pBlitter);
2068 m_pBlitter = NULL;
2069
2070 COCOA_LOG_FLOW(("%s: returns false - CrBltInit failed with rc=%Rrc\n", __PRETTY_FUNCTION__, rc));
2071 return false;
2072 }
2073
2074 COCOA_LOG_FLOW(("%s: blitter (%p) created successfully for view 0x%p\n", (void *)m_pBlitter, (void *)self));
2075
2076 /* Create a shared context out of the main context. Use the same pixel format. */
2077 NSOpenGLPixelFormat *pPixelFormat = [(OverlayOpenGLContext *)m_pGLCtx openGLPixelFormat];
2078 NSOpenGLContext *pSharedGLCtx = [[NSOpenGLContext alloc] initWithFormat:pPixelFormat shareContext:m_pGLCtx];
2079
2080 /* Set the new context as non opaque */
2081 GLint opaque = 0;
2082 [pSharedGLCtx setValues:&opaque forParameter:NSOpenGLCPSurfaceOpacity];
2083
2084 /* Set this view as the drawable for the new context */
2085 [pSharedGLCtx setView:self];
2086 m_fNeedViewportUpdate = true;
2087
2088 m_pSharedGLCtx = pSharedGLCtx;
2089
2090 COCOA_LOG_FLOW(("%s: returns true - new m_pSharedGLCtx=%p\n", __PRETTY_FUNCTION__, (void *)m_pSharedGLCtx));
2091 return true;
2092}
2093
2094- (void)vboxTryDraw
2095{
2096 COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
2097
2098 glFlush();
2099
2100 /* Issue to the gui thread. */
2101 [self performSelectorOnMainThread:@selector(vboxTryDrawUI) withObject:nil waitUntilDone:NO];
2102
2103 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
2104}
2105
2106- (void)vboxSetVisible:(GLboolean)fVisible
2107{
2108 COCOA_LOG_FLOW(("%s: self=%p fVisible=%d\n", __PRETTY_FUNCTION__, (void *)self, fVisible));
2109
2110 VBoxMainThreadTaskRunner *pRunner = [VBoxMainThreadTaskRunner globalInstance];
2111 NSNumber *pVisObj = [NSNumber numberWithBool:fVisible];
2112 [pRunner addObj:self selector:@selector(vboxSetVisibleUIObj:) arg:pVisObj];
2113
2114 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
2115}
2116
2117- (void)vboxSetVisibleUI:(GLboolean)fVisible
2118{
2119 COCOA_LOG_FLOW(("%s: self=%p fVisible=%d\n", __PRETTY_FUNCTION__, (void *)self, fVisible));
2120
2121 [self setHidden: !fVisible];
2122
2123 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
2124}
2125
2126- (void)vboxSetVisibleUIObj:(NSNumber *)pVisibleObj
2127{
2128 COCOA_LOG_FLOW(("%s: self=%p pVisibleObj=%p(%d)\n", __PRETTY_FUNCTION__,
2129 (void *)self, (void *)pVisibleObj, [pVisibleObj boolValue]));
2130
2131 BOOL fVisible = [pVisibleObj boolValue];
2132 [self vboxSetVisibleUI:fVisible];
2133
2134 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
2135}
2136
2137- (void)vboxReparent:(NSView *)pParentView
2138{
2139 COCOA_LOG_FLOW(("%s: self=%p pParentView=%p\n", __PRETTY_FUNCTION__, (void *)self, (void *)pParentView));
2140
2141 VBoxMainThreadTaskRunner *pRunner = [VBoxMainThreadTaskRunner globalInstance];
2142 [pRunner addObj:self selector:@selector(vboxReparentUI:) arg:pParentView];
2143
2144 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
2145}
2146
2147- (void)vboxReparentUI:(NSView *)pParentView
2148{
2149 COCOA_LOG_FLOW(("%s: self=%p pParentView=%p\n", __PRETTY_FUNCTION__, (void *)self, (void *)pParentView));
2150
2151 /* Make sure the window is removed from any previous parent window. */
2152 if ([[self overlayWin] parentWindow] != nil)
2153 {
2154 [[[self overlayWin] parentWindow] removeChildWindow:[self overlayWin]];
2155 }
2156
2157 /* Set the new parent view */
2158 [self setParentView: pParentView];
2159
2160 /* Add the overlay window as a child to the new parent window */
2161 if (pParentView != nil)
2162 {
2163 [[pParentView window] addChildWindow:[self overlayWin] ordered:NSWindowAbove];
2164 if ([self isEverSized])
2165 [self vboxReshapeOnReparentPerform];
2166 }
2167
2168 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
2169}
2170
2171- (void)vboxTryDrawUI
2172{
2173 COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
2174
2175 if ([self isHidden])
2176 {
2177 COCOA_LOG_FLOW(("%s: returns - request to draw on a hidden view\n", __PRETTY_FUNCTION__));
2178 return;
2179 }
2180
2181 if ([[self overlayWin] parentWindow] == nil)
2182 {
2183 COCOA_LOG_FLOW(("%s: returns - request to draw a view w/o a parent\n", __PRETTY_FUNCTION__));
2184 return;
2185 }
2186
2187#ifdef IN_VMSVGA3D
2188 if (!m_pSharedGLCtx)
2189 {
2190 Assert(!m_fDataVisible);
2191 Assert(!m_fCleanupNeeded);
2192 if (![self vboxSharedCtxCreate])
2193 {
2194 COCOA_LOG_FLOW(("%s: returns - vboxSharedCtxCreate failed\n", __PRETTY_FUNCTION__));
2195 return;
2196 }
2197 Assert(m_pSharedGLCtx);
2198 }
2199#endif
2200
2201 const VBOXVR_SCR_COMPOSITOR *pCompositor;
2202 int rc = renderspuVBoxCompositorLock(m_pWinInfo, &pCompositor);
2203 if (RT_FAILURE(rc))
2204 {
2205 COCOA_LOG_FLOW(("%s: returns - renderspuVBoxCompositorLock failed (%Rrc)\n", __PRETTY_FUNCTION__, rc));
2206 return;
2207 }
2208
2209#ifndef IN_VMSVGA3D
2210 if (!pCompositor && !m_fCleanupNeeded)
2211 {
2212 renderspuVBoxCompositorUnlock(m_pWinInfo);
2213 COCOA_LOG_FLOW(("%s: returns - noCompositorUI\n", __PRETTY_FUNCTION__));
2214 return;
2215 }
2216#endif
2217
2218 VBOXVR_SCR_COMPOSITOR TmpCompositor;
2219
2220 if (pCompositor)
2221 {
2222 if (!m_pSharedGLCtx)
2223 {
2224 Assert(!m_fDataVisible);
2225 Assert(!m_fCleanupNeeded);
2226 renderspuVBoxCompositorRelease(m_pWinInfo);
2227 if (![self vboxSharedCtxCreate])
2228 {
2229 COCOA_LOG_FLOW(("%s: returns - vboxSharedCtxCreate failed\n", __PRETTY_FUNCTION__));
2230 return;
2231 }
2232
2233 Assert(m_pSharedGLCtx);
2234
2235 pCompositor = renderspuVBoxCompositorAcquire(m_pWinInfo);
2236 Assert(!m_fDataVisible);
2237 Assert(!m_fCleanupNeeded);
2238 if (!pCompositor)
2239 {
2240 COCOA_LOG_FLOW(("%s: returns - Failed to reacquire compositor\n", __PRETTY_FUNCTION__));
2241 return;
2242 }
2243 }
2244 }
2245 else
2246 {
2247 DEBUG_MSG(("%s: NeedCleanup\n", __PRETTY_FUNCTION__));
2248#ifndef IN_VMSVGA3D /** @todo VMSVGA3 */
2249 Assert(m_fCleanupNeeded);
2250#endif
2251 CrVrScrCompositorInit(&TmpCompositor, NULL);
2252 pCompositor = &TmpCompositor;
2253 }
2254
2255 if ([self lockFocusIfCanDraw])
2256 {
2257 COCOA_LOG_FLOW(("%s: Calling vboxPresent\n", __PRETTY_FUNCTION__));
2258 [self vboxPresent:pCompositor];
2259 [self unlockFocus];
2260 }
2261#ifndef IN_VMSVGA3D /** @todo VMSVGA3 */
2262 else if (!m_pWinInfo->visible)
2263 {
2264 COCOA_LOG_FLOW(("%s: NotVisible\n", __PRETTY_FUNCTION__));
2265 m_fCleanupNeeded = false;
2266 }
2267#endif
2268 else
2269 {
2270 COCOA_LOG_FLOW(("%s: Reschedule\n", __PRETTY_FUNCTION__));
2271 [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(vboxTryDrawUI) userInfo:nil repeats:NO];
2272 }
2273
2274 renderspuVBoxCompositorUnlock(m_pWinInfo);
2275 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
2276}
2277
2278- (void)swapFBO
2279{
2280 COCOA_LOG_FLOW(("%s: self=%p - m_pGLCtx=%p\n", __PRETTY_FUNCTION__, (void *)self, (void *)m_pGLCtx));
2281 [m_pGLCtx flushBuffer];
2282 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
2283}
2284
2285- (void)vboxPresent:(PCVBOXVR_SCR_COMPOSITOR)pCompositor
2286{
2287 COCOA_LOG_FLOW(("%s: self=%p pCompositor=%p\n", __PRETTY_FUNCTION__, (void *)self, (void *)pCompositor));
2288 /*DEBUG_MSG(("OVIW(%p): renderFBOToView\n", (void *)self));*/
2289 AssertPtr(pCompositor);
2290
2291 VBOX_CR_RENDER_CTX_INFO CtxInfo;
2292 vboxCtxEnter(m_pSharedGLCtx, &CtxInfo);
2293
2294 [self vboxPresentCS:pCompositor];
2295
2296 vboxCtxLeave(&CtxInfo);
2297 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
2298}
2299
2300- (void)vboxPresentCS:(PCVBOXVR_SCR_COMPOSITOR)pCompositor
2301{
2302 COCOA_LOG_FLOW(("%s: self=%p pCompositor=%p\n", __PRETTY_FUNCTION__, (void *)self, (void *)pCompositor));
2303 if ([m_pSharedGLCtx view] != self)
2304 {
2305 COCOA_LOG_FLOW(("%s: Not current view of shared ctx! Switching... (self=%p, view=%p, m_pSharedGLCtx)\n",
2306 __PRETTY_FUNCTION__, (void *)self, (void *)[m_pSharedGLCtx view], (void *)m_pSharedGLCtx));
2307 [m_pSharedGLCtx setView: self];
2308 m_fNeedViewportUpdate = true;
2309 }
2310
2311 if (m_fNeedViewportUpdate)
2312 {
2313 [self updateViewportCS];
2314 m_fNeedViewportUpdate = false;
2315 }
2316
2317 m_fCleanupNeeded = false;
2318
2319 /* Render FBO content to the dock tile when necessary. */
2320 [self vboxPresentToDockTileCS:pCompositor];
2321
2322 /* change to #if 0 to see thumbnail image */
2323#if 1
2324 [self vboxPresentToViewCS:pCompositor];
2325#else
2326 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
2327 [m_pSharedGLCtx flushBuffer];
2328#endif
2329
2330 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
2331}
2332
2333DECLINLINE(void) vboxNSRectToRect(const NSRect *pR, RTRECT *pRect)
2334{
2335 pRect->xLeft = (int)pR->origin.x;
2336 pRect->yTop = (int)pR->origin.y;
2337 pRect->xRight = (int)(pR->origin.x + pR->size.width);
2338 pRect->yBottom = (int)(pR->origin.y + pR->size.height);
2339}
2340
2341DECLINLINE(void) vboxNSRectToRectUnstretched(const NSRect *pR, RTRECT *pRect, float xStretch, float yStretch)
2342{
2343 pRect->xLeft = (int)(pR->origin.x / xStretch);
2344 pRect->yTop = (int)(pR->origin.y / yStretch);
2345 pRect->xRight = (int)((pR->origin.x + pR->size.width) / xStretch);
2346 pRect->yBottom = (int)((pR->origin.y + pR->size.height) / yStretch);
2347}
2348
2349DECLINLINE(void) vboxNSRectToRectStretched(const NSRect *pR, RTRECT *pRect, float xStretch, float yStretch)
2350{
2351 pRect->xLeft = (int)(pR->origin.x * xStretch);
2352 pRect->yTop = (int)(pR->origin.y * yStretch);
2353 pRect->xRight = (int)((pR->origin.x + pR->size.width) * xStretch);
2354 pRect->yBottom = (int)((pR->origin.y + pR->size.height) * yStretch);
2355}
2356
2357- (void)vboxPresentToViewCS:(PCVBOXVR_SCR_COMPOSITOR)pCompositor
2358{
2359 NSRect r = [self frame];
2360 COCOA_LOG_FLOW(("%s: self=%p - r={%d,%d %d,%d}\n", __PRETTY_FUNCTION__, (void *)self,
2361 (int)r.origin.x, (int)r.origin.y, (int)r.size.width, (int)r.size.height));
2362
2363#if 1 /* Set to 0 to see the docktile instead of the real output */
2364 VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR CIter;
2365 const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry;
2366
2367 CrVrScrCompositorConstIterInit(pCompositor, &CIter);
2368
2369 float backingStretchFactor = 1.;
2370#if defined(VBOX_WITH_CONFIGURABLE_HIDPI_SCALING) && !defined(IN_VMSVGA3D)
2371 /* Adjust viewport according to current NSView's backing store parameters. */
2372 crDebug("HiDPI: vboxPresentToViewCS: up-scaling is %s.", render_spu.fUnscaledHiDPI ? "OFF" : "ON");
2373 if (render_spu.fUnscaledHiDPI)
2374 {
2375 NSRect regularBounds = [self bounds];
2376 NSRect backingBounds = [self safeConvertRectToBacking:&regularBounds];
2377 glViewport(0, 0, backingBounds.size.width, backingBounds.size.height);
2378
2379 /* Update stretch factor in order to satisfy current NSView's backing store parameters. */
2380 backingStretchFactor = [self safeGetBackingScaleFactor];
2381 }
2382 else
2383 backingStretchFactor = 1.;
2384#endif
2385
2386 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
2387 glDrawBuffer(GL_BACK);
2388
2389 /* Clear background to transparent */
2390 glClear(GL_COLOR_BUFFER_BIT);
2391
2392 m_fDataVisible = false;
2393
2394 float xStretch;
2395 float yStretch;
2396 CrVrScrCompositorGetStretching(pCompositor, &xStretch, &yStretch);
2397
2398 while ((pEntry = CrVrScrCompositorConstIterNext(&CIter)) != NULL)
2399 {
2400 uint32_t cRegions;
2401 const RTRECT *paSrcRegions, *paDstRegions;
2402 int rc = CrVrScrCompositorEntryRegionsGet(pCompositor, pEntry, &cRegions, &paSrcRegions, &paDstRegions, NULL);
2403 uint32_t fFlags = CrVrScrCompositorEntryFlagsCombinedGet(pCompositor, pEntry);
2404 if (RT_SUCCESS(rc))
2405 {
2406 rc = CrBltEnter(m_pBlitter);
2407 if (RT_SUCCESS(rc))
2408 {
2409 uint32_t i;
2410 for (i = 0; i < cRegions; ++i)
2411 {
2412 const CR_TEXDATA *pTexData;
2413 PCRTRECT pSrcRect = &paSrcRegions[i];
2414 PCRTRECT pDstRect = &paDstRegions[i];
2415 RTRECT DstRect, RestrictDstRect;
2416 RTRECT SrcRect, RestrictSrcRect;
2417
2418 vboxNSRectToRect(&m_RootRect, &RestrictDstRect);
2419 VBoxRectIntersected(&RestrictDstRect, pDstRect, &DstRect);
2420
2421 if (VBoxRectIsZero(&DstRect))
2422 continue;
2423
2424 VBoxRectTranslate(&DstRect, -RestrictDstRect.xLeft, -RestrictDstRect.yTop);
2425
2426 vboxNSRectToRectUnstretched(&m_RootRect, &RestrictSrcRect, xStretch / backingStretchFactor, yStretch / backingStretchFactor);
2427 VBoxRectTranslate(&RestrictSrcRect,
2428 -CrVrScrCompositorEntryRectGet(pEntry)->xLeft,
2429 -CrVrScrCompositorEntryRectGet(pEntry)->yTop);
2430 VBoxRectIntersected(&RestrictSrcRect, pSrcRect, &SrcRect);
2431
2432 if (VBoxRectIsZero(&SrcRect))
2433 continue;
2434
2435 pSrcRect = &SrcRect;
2436 pDstRect = &DstRect;
2437
2438 pTexData = CrVrScrCompositorEntryTexGet(pEntry);
2439
2440 CrBltBlitTexMural(m_pBlitter, true, CrTdTexGet(pTexData), pSrcRect, pDstRect, 1, fFlags | CRBLT_F_NOALPHA);
2441
2442 m_fDataVisible = true;
2443 }
2444 CrBltLeave(m_pBlitter);
2445 }
2446 else
2447 {
2448 DEBUG_WARN(("CrBltEnter failed rc %d", rc));
2449# ifndef DEBUG_VERBOSE
2450 AssertMsgFailed(("CrBltEnter failed rc %Rrc", rc));
2451# endif
2452 }
2453 }
2454 else
2455 {
2456 AssertMsgFailed(("BlitStretched: CrVrScrCompositorEntryRegionsGet failed rc %Rrc\n", rc));
2457 DEBUG_MSG_1(("BlitStretched: CrVrScrCompositorEntryRegionsGet failed rc %d\n", rc));
2458 }
2459 }
2460#endif
2461
2462 /*
2463 glFinish();
2464 */
2465 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
2466 [m_pSharedGLCtx flushBuffer];
2467
2468 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
2469}
2470
2471- (void)presentComposition:(PCVBOXVR_SCR_COMPOSITOR_ENTRY)pChangedEntry
2472{
2473 COCOA_LOG_FLOW(("%s: self=%p pChangedEntry=%p\n", __PRETTY_FUNCTION__, (void *)self, (void *)pChangedEntry));
2474 [self vboxTryDraw];
2475}
2476
2477- (void)vboxBlitterSyncWindow
2478{
2479 COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
2480 CR_BLITTER_WINDOW WinInfo;
2481 NSRect r;
2482
2483 if (!m_pBlitter)
2484 return;
2485
2486 RT_ZERO(WinInfo);
2487
2488 r = [self frame];
2489 WinInfo.width = r.size.width;
2490 WinInfo.height = r.size.height;
2491
2492 Assert(WinInfo.width == m_RootRect.size.width);
2493 Assert(WinInfo.height == m_RootRect.size.height);
2494
2495 /*CrBltMuralSetCurrentInfo(m_pBlitter, NULL);*/
2496
2497 CrBltMuralSetCurrentInfo(m_pBlitter, &WinInfo);
2498 CrBltCheckUpdateViewport(m_pBlitter);
2499}
2500
2501#ifdef VBOX_WITH_CRDUMPER_THUMBNAIL
2502static int g_cVBoxTgaCtr = 0;
2503#endif
2504- (void)vboxPresentToDockTileCS:(PCVBOXVR_SCR_COMPOSITOR)pCompositor
2505{
2506 COCOA_LOG_FLOW(("%s: self=%p pCompositor=%p\n", __PRETTY_FUNCTION__, (void *)self, (void *)pCompositor));
2507 NSRect r = [self frame];
2508 NSRect rr = NSZeroRect;
2509 NSDockTile *pDT = nil;
2510 float xStretch;
2511 float yStretch;
2512
2513 if ([m_DockTileView thumbBitmap] != nil)
2514 {
2515 /*
2516 * Only update after at least 200 ms, cause glReadPixels is
2517 * heavy performance wise.
2518 */
2519 uint64_t msTS = RTTimeSystemMilliTS();
2520 VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR CIter;
2521 const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry;
2522
2523 if (msTS - m_msDockUpdateTS > 200)
2524 {
2525 m_msDockUpdateTS = msTS;
2526#if 0
2527 /* todo: check this for optimization */
2528 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, myTextureName);
2529 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_STORAGE_HINT_APPLE,
2530 GL_STORAGE_SHARED_APPLE);
2531 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2532 glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA,
2533 sizex, sizey, 0, GL_BGRA,
2534 GL_UNSIGNED_INT_8_8_8_8_REV, myImagePtr);
2535 glCopyTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB,
2536 0, 0, 0, 0, 0, image_width, image_height);
2537 glFlush();
2538 /* Do other work processing here, using a double or triple buffer */
2539 glGetTexImage(GL_TEXTURE_RECTANGLE_ARB, 0, GL_BGRA,
2540 GL_UNSIGNED_INT_8_8_8_8_REV, pixels);
2541#endif
2542 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
2543 glDrawBuffer(GL_BACK);
2544
2545 /* Clear background to transparent */
2546 glClear(GL_COLOR_BUFFER_BIT);
2547
2548 rr = [m_DockTileView frame];
2549
2550 CrVrScrCompositorGetStretching(pCompositor, &xStretch, &yStretch);
2551
2552 CrVrScrCompositorConstIterInit(pCompositor, &CIter);
2553 while ((pEntry = CrVrScrCompositorConstIterNext(&CIter)) != NULL)
2554 {
2555 uint32_t cRegions;
2556 PCRTRECT paSrcRegions;
2557 PCRTRECT paDstRegions;
2558 int rc = CrVrScrCompositorEntryRegionsGet(pCompositor, pEntry, &cRegions, &paSrcRegions, &paDstRegions, NULL);
2559 uint32_t fFlags = CrVrScrCompositorEntryFlagsCombinedGet(pCompositor, pEntry);
2560 if (RT_SUCCESS(rc))
2561 {
2562 rc = CrBltEnter(m_pBlitter);
2563 if (RT_SUCCESS(rc))
2564 {
2565 uint32_t i;
2566 for (i = 0; i < cRegions; ++i)
2567 {
2568 const CR_TEXDATA *pTexData;
2569 PCRTRECT pSrcRect = &paSrcRegions[i];
2570 PCRTRECT pDstRect = &paDstRegions[i];
2571 RTRECT DstRect, RestrictDstRect;
2572 RTRECT SrcRect, RestrictSrcRect;
2573
2574 vboxNSRectToRect(&m_RootRect, &RestrictDstRect);
2575 VBoxRectIntersected(&RestrictDstRect, pDstRect, &DstRect);
2576
2577 VBoxRectTranslate(&DstRect, -RestrictDstRect.xLeft, -RestrictDstRect.yTop);
2578
2579 VBoxRectScale(&DstRect, m_FBOThumbScaleX, m_FBOThumbScaleY);
2580
2581 if (VBoxRectIsZero(&DstRect))
2582 continue;
2583
2584 vboxNSRectToRectUnstretched(&m_RootRect, &RestrictSrcRect, xStretch, yStretch);
2585 VBoxRectTranslate(&RestrictSrcRect,
2586 -CrVrScrCompositorEntryRectGet(pEntry)->xLeft,
2587 -CrVrScrCompositorEntryRectGet(pEntry)->yTop);
2588 VBoxRectIntersected(&RestrictSrcRect, pSrcRect, &SrcRect);
2589
2590 if (VBoxRectIsZero(&SrcRect))
2591 continue;
2592
2593 pSrcRect = &SrcRect;
2594 pDstRect = &DstRect;
2595
2596 pTexData = CrVrScrCompositorEntryTexGet(pEntry);
2597
2598 CrBltBlitTexMural(m_pBlitter, true, CrTdTexGet(pTexData), pSrcRect, pDstRect, 1, fFlags);
2599 }
2600 CrBltLeave(m_pBlitter);
2601 }
2602 else
2603 {
2604 DEBUG_WARN(("CrBltEnter failed rc %d", rc));
2605#ifndef DEBUG_VERBOSE
2606 AssertMsgFailed(("CrBltEnter failed rc %Rrc", rc));
2607#endif
2608 }
2609 }
2610 else
2611 {
2612 DEBUG_MSG_1(("BlitStretched: CrVrScrCompositorEntryRegionsGet failed rc %d\n", rc));
2613 AssertMsgFailed(("BlitStretched: CrVrScrCompositorEntryRegionsGet failed rc %Rrc\n", rc));
2614 }
2615 }
2616
2617 glFinish();
2618
2619 glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
2620 glReadBuffer(GL_BACK);
2621
2622 /* Here the magic of reading the FBO content in our own buffer
2623 * happens. We have to lock this access, in the case the dock
2624 * is updated currently. */
2625 [m_DockTileView lock];
2626 glReadPixels(0, m_RootRect.size.height - rr.size.height, rr.size.width, rr.size.height,
2627 GL_BGRA,
2628 GL_UNSIGNED_INT_8_8_8_8,
2629 [[m_DockTileView thumbBitmap] bitmapData]);
2630 [m_DockTileView unlock];
2631
2632#ifdef VBOX_WITH_CRDUMPER_THUMBNAIL
2633 ++g_cVBoxTgaCtr;
2634 crDumpNamedTGAF((GLint)rr.size.width, (GLint)rr.size.height,
2635 [[m_DockTileView thumbBitmap] bitmapData], "/Users/leo/vboxdumps/dump%d.tga", g_cVBoxTgaCtr);
2636#endif
2637
2638 pDT = [[NSApplication sharedApplication] dockTile];
2639
2640 /* Send a display message to the dock tile in the main thread */
2641 [[[NSApplication sharedApplication] dockTile] performSelectorOnMainThread:@selector(display) withObject:nil
2642 waitUntilDone:NO];
2643 }
2644 }
2645}
2646
2647- (void)clearVisibleRegions
2648{
2649 if (m_paClipRects)
2650 {
2651 RTMemFree(m_paClipRects);
2652 m_paClipRects = NULL;
2653 }
2654 m_cClipRects = 0;
2655}
2656
2657- (GLboolean)vboxNeedsEmptyPresent
2658{
2659 if (m_fDataVisible)
2660 {
2661 m_fCleanupNeeded = true;
2662 return GL_TRUE;
2663 }
2664
2665 return GL_FALSE;
2666}
2667
2668- (void)setVisibleRegions:(GLint)cRects paRects:(const GLint *)paRects
2669{
2670 COCOA_LOG_FLOW(("%s: self=%p cRects=%d paRects=%p\n", __PRETTY_FUNCTION__, (void *)self, cRects, (void *)paRects));
2671 GLint cOldRects = m_cClipRects;
2672
2673 [self clearVisibleRegions];
2674
2675 if (cRects > 0)
2676 {
2677#ifdef DEBUG_poetzsch
2678 int i = 0;
2679 for (i = 0; i < cRects; ++i)
2680 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]));
2681#endif
2682
2683 m_paClipRects = (GLint *)RTMemDup(paRects, sizeof(GLint) * 4 * cRects);
2684 m_cClipRects = cRects;
2685 }
2686
2687 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
2688}
2689
2690- (NSView *)dockTileScreen
2691{
2692 COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
2693 NSView *pContentView = [[[NSApplication sharedApplication] dockTile] contentView];
2694 NSView *pScreenContent = nil;
2695
2696 /*
2697 * First try the new variant which checks if this window is within the
2698 * screen which is previewed in the dock.
2699 */
2700 if ([pContentView respondsToSelector:@selector(screenContentWithParentView:)])
2701 pScreenContent = [pContentView performSelector:@selector(screenContentWithParentView:) withObject:(id)m_pParentView];
2702 /*
2703 * If it fails, fall back to the old variant (VBox...).
2704 */
2705 else if ([pContentView respondsToSelector:@selector(screenContent)])
2706 pScreenContent = [pContentView performSelector:@selector(screenContent)];
2707
2708 COCOA_LOG_FLOW(("%s: returns %p (pContentView=%p)\n", __PRETTY_FUNCTION__, (void *)pScreenContent, (void *)pContentView));
2709 return pScreenContent;
2710}
2711
2712- (void)reshapeDockTile
2713{
2714 COCOA_LOG_FLOW(("%s:\n", __PRETTY_FUNCTION__));
2715 NSRect newFrame = NSZeroRect;
2716 NSView *pView = [self dockTileScreen];
2717 if (pView != nil)
2718 {
2719 NSRect dockFrame = [pView frame];
2720 /** @todo This is not correct, we should use framebuffer size here, while
2721 * parent view frame size may differ in case of scrolling. */
2722 NSRect parentFrame = [m_pParentView frame];
2723
2724 m_FBOThumbScaleX = (float)dockFrame.size.width / parentFrame.size.width;
2725 m_FBOThumbScaleY = (float)dockFrame.size.height / parentFrame.size.height;
2726 newFrame = NSMakeRect((int)(m_Pos.x * m_FBOThumbScaleX),
2727 (int)(dockFrame.size.height - (m_Pos.y + m_Size.height - m_yInvRootOffset) * m_FBOThumbScaleY),
2728 (int)(m_Size.width * m_FBOThumbScaleX),
2729 (int)(m_Size.height * m_FBOThumbScaleY));
2730 /*
2731 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));
2732 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));
2733 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);
2734 */
2735 [m_DockTileView setFrame: newFrame];
2736 }
2737 COCOA_LOG_FLOW(("%s: returns - newFrame={%d,%d %d,%d} pView=%d\n", __PRETTY_FUNCTION__, (int)newFrame.origin.x,
2738 (int)newFrame.origin.y, (int)newFrame.size.width, (int)newFrame.size.height, (void *)pView));
2739}
2740
2741@end /* @implementation OverlayView */
2742
2743
2744/********************************************************************************
2745*
2746* OpenGL context management
2747*
2748********************************************************************************/
2749void cocoaGLCtxCreate(NativeNSOpenGLContextRef *ppCtx, GLbitfield fVisParams, NativeNSOpenGLContextRef pSharedCtx)
2750{
2751 COCOA_LOG_FLOW(("cocoaGLCtxCreate: ppCtx=%p fVisParams=%#x pSharedCtx=%p\n", (void *)ppCtx, fVisParams, (void *)pSharedCtx));
2752 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
2753 NSOpenGLPixelFormat *pFmt = nil;
2754
2755 NSOpenGLPixelFormatAttribute attribs[24] =
2756 {
2757#ifdef IN_VMSVGA3D
2758 NSOpenGLPFAOpenGLProfile, (NSOpenGLPixelFormatAttribute)0,
2759#endif
2760 NSOpenGLPFAAccelerated,
2761 NSOpenGLPFAColorSize, (NSOpenGLPixelFormatAttribute)24
2762 };
2763
2764 int i = 3;
2765
2766#ifdef IN_VMSVGA3D
2767 if (fVisParams & VMSVGA3D_NON_DEFAULT_PROFILE_BIT)
2768 attribs[1] = VBOX_VMSVGA3D_DEFAULT_OGL_PROFILE >= 3.2 ? NSOpenGLProfileVersionLegacy : NSOpenGLProfileVersion3_2Core;
2769 else
2770 attribs[1] = VBOX_VMSVGA3D_DEFAULT_OGL_PROFILE >= 3.2 ? NSOpenGLProfileVersion3_2Core : NSOpenGLProfileVersionLegacy;
2771#endif
2772
2773 if (fVisParams & CR_ALPHA_BIT)
2774 {
2775 COCOA_LOG_FLOW((" CR_ALPHA_BIT requested\n"));
2776 attribs[i++] = NSOpenGLPFAAlphaSize;
2777 attribs[i++] = 8;
2778 }
2779 if (fVisParams & CR_DEPTH_BIT)
2780 {
2781 COCOA_LOG_FLOW((" CR_DEPTH_BIT requested\n"));
2782 attribs[i++] = NSOpenGLPFADepthSize;
2783 attribs[i++] = 24;
2784 }
2785 if (fVisParams & CR_STENCIL_BIT)
2786 {
2787 COCOA_LOG_FLOW((" CR_STENCIL_BIT requested\n"));
2788 attribs[i++] = NSOpenGLPFAStencilSize;
2789 attribs[i++] = 8;
2790 }
2791 if (fVisParams & CR_ACCUM_BIT)
2792 {
2793 COCOA_LOG_FLOW((" CR_ACCUM_BIT requested\n"));
2794 attribs[i++] = NSOpenGLPFAAccumSize;
2795 if (fVisParams & CR_ALPHA_BIT)
2796 attribs[i++] = 32;
2797 else
2798 attribs[i++] = 24;
2799 }
2800 if (fVisParams & CR_MULTISAMPLE_BIT)
2801 {
2802 COCOA_LOG_FLOW((" CR_MULTISAMPLE_BIT requested\n"));
2803 attribs[i++] = NSOpenGLPFASampleBuffers;
2804 attribs[i++] = 1;
2805 attribs[i++] = NSOpenGLPFASamples;
2806 attribs[i++] = 4;
2807 }
2808 if (fVisParams & CR_DOUBLE_BIT)
2809 {
2810 COCOA_LOG_FLOW((" CR_DOUBLE_BIT requested\n"));
2811 attribs[i++] = NSOpenGLPFADoubleBuffer;
2812 }
2813 if (fVisParams & CR_STEREO_BIT)
2814 {
2815 /* We don't support that.
2816 COCOA_LOG_FLOW((" CR_STEREO_BIT requested\n"));
2817 attribs[i++] = NSOpenGLPFAStereo;
2818 */
2819 }
2820
2821 if (VBoxOglIsOfflineRenderingAppropriate())
2822 {
2823 COCOA_LOG_FLOW((" Offline rendering is enabled\n"));
2824 attribs[i++] = NSOpenGLPFAAllowOfflineRenderers;
2825 }
2826
2827 /* Mark the end */
2828 attribs[i++] = 0;
2829
2830 /* Choose a pixel format */
2831 pFmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
2832
2833 if (pFmt)
2834 {
2835 *ppCtx = [[OverlayOpenGLContext alloc] initWithFormat:pFmt shareContext:pSharedCtx];
2836 Assert(*ppCtx);
2837
2838 /* Enable multi threaded OpenGL engine */
2839 /*
2840 CGLContextObj cglCtx = [*ppCtx CGLContextObj];
2841 CGLError err = CGLEnable(cglCtx, kCGLCEMPEngine);
2842 if (err != kCGLNoError)
2843 printf ("Couldn't enable MT OpenGL engine!\n");
2844 */
2845 }
2846 else
2847 {
2848 AssertFailed();
2849 *ppCtx = NULL;
2850 }
2851
2852 [pPool release];
2853 COCOA_LOG_FLOW(("cocoaGLCtxDestroy: returns *ppCtx=%p\n", (void *)*ppCtx));
2854}
2855
2856void cocoaGLCtxDestroy(NativeNSOpenGLContextRef pCtx)
2857{
2858 COCOA_LOG_FLOW(("cocoaGLCtxDestroy: pCtx=%p\n", (void *)pCtx));
2859 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
2860
2861 [pCtx release];
2862 /*[pCtx performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO];*/
2863
2864 [pPool release];
2865 COCOA_LOG_FLOW(("cocoaGLCtxDestroy: returns\n"));
2866}
2867
2868/********************************************************************************
2869*
2870* View management
2871*
2872********************************************************************************/
2873static OverlayView *vboxViewCreate(WindowInfo *pWinInfo, NativeNSViewRef pParentView)
2874{
2875 COCOA_LOG_FLOW(("vboxViewCreate: pWinInfo=%p pParentView=%p\n", pWinInfo, (void *)pParentView));
2876
2877 /* Create our worker view. */
2878 OverlayView *pView = [[OverlayView alloc] initWithFrame:NSZeroRect
2879 thread:RTThreadSelf()
2880 parentView:pParentView
2881 winInfo:pWinInfo];
2882
2883 if (pView)
2884 {
2885 /* We need a real window as container for the view */
2886 [[OverlayWindow alloc] initWithParentView:pParentView overlayView:pView];
2887 /* Return the freshly created overlay view */
2888 COCOA_LOG_FLOW(("vboxViewCreate: returns %p\n", (void *)pView));
2889 return pView;
2890 }
2891
2892 COCOA_LOG_FLOW(("vboxViewCreate: returns NULL\n"));
2893 return NULL;
2894}
2895
2896#ifndef IN_VMSVGA3D
2897
2898typedef struct CR_RCD_CREATEVIEW
2899{
2900 WindowInfo *pWinInfo;
2901 NSView *pParentView;
2902 GLbitfield fVisParams;
2903 /* out */
2904 OverlayView *pView;
2905} CR_RCD_CREATEVIEW;
2906
2907static DECLCALLBACK(void) vboxRcdCreateView(void *pvCb)
2908{
2909 CR_RCD_CREATEVIEW *pCreateView = (CR_RCD_CREATEVIEW *)pvCb;
2910 pCreateView->pView = vboxViewCreate(pCreateView->pWinInfo, pCreateView->pParentView);
2911 COCOA_LOG_FLOW(("vboxRcdCreateView: returns pView=%p\n", (void *)pCreateView->pView));
2912}
2913
2914#endif /* !IN_VMSVGA3D */
2915
2916void cocoaViewCreate(NativeNSViewRef *ppView, WindowInfo *pWinInfo, NativeNSViewRef pParentView, GLbitfield fVisParams)
2917{
2918 COCOA_LOG_FLOW(("cocoaViewCreate: ppView=%p pWinInfo=%p pParentView=%p fVisParams=%#x\n",
2919 (void *)ppView, (void *)pWinInfo, (void *)pParentView, fVisParams));
2920 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
2921
2922 /* make sure all tasks are run, to preserve the order */
2923 VBoxMainThreadTaskRunner *pRunner = [VBoxMainThreadTaskRunner globalInstance];
2924 [pRunner runTasksSyncIfPossible];
2925
2926 renderspuWinRetain(pWinInfo);
2927
2928#ifndef IN_VMSVGA3D
2929 if (renderspuCalloutAvailable())
2930 {
2931 CR_RCD_CREATEVIEW CreateView;
2932 CreateView.pWinInfo = pWinInfo;
2933 CreateView.pParentView = pParentView;
2934 CreateView.fVisParams = fVisParams;
2935 CreateView.pView = NULL;
2936 renderspuCalloutClient(vboxRcdCreateView, &CreateView);
2937 *ppView = CreateView.pView;
2938 }
2939 else
2940#endif
2941 {
2942 DEBUG_MSG_NOT_VMSVGA3D(("no callout available on createWindow\n"));
2943#if 0
2944 dispatch_sync(dispatch_get_main_queue(), ^{
2945#endif
2946 *ppView = vboxViewCreate(pWinInfo, pParentView);
2947#if 0
2948 });
2949#endif
2950 }
2951
2952 if (!*ppView)
2953 renderspuWinRelease(pWinInfo);
2954
2955 [pPool release];
2956 COCOA_LOG_FLOW(("cocoaViewCreate: returns *ppView=%p\n", (void *)*ppView));
2957}
2958
2959void cocoaViewReparent(NativeNSViewRef pView, NativeNSViewRef pParentView)
2960{
2961 COCOA_LOG_FLOW(("cocoaViewReparent: pView=%p pParentView=%p\n", (void *)pView, (void *)pParentView));
2962 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
2963
2964 OverlayView *pOView = (OverlayView *)pView;
2965 if (pOView)
2966 [pOView vboxReparent:pParentView];
2967
2968 [pPool release];
2969 COCOA_LOG_FLOW(("cocoaViewReparent: returns\n"));
2970}
2971
2972void cocoaViewDestroy(NativeNSViewRef pView)
2973{
2974 COCOA_LOG_FLOW(("cocoaViewDestroy: pView=%p\n", (void *)pView));
2975 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
2976
2977 VBoxMainThreadTaskRunner *pRunner = [VBoxMainThreadTaskRunner globalInstance];
2978 [pRunner addObj:pView selector:@selector(vboxDestroy) arg:nil];
2979
2980 [pPool release];
2981 COCOA_LOG_FLOW(("cocoaViewDestroy: returns\n"));
2982}
2983
2984void cocoaViewShow(NativeNSViewRef pView, GLboolean fShowIt)
2985{
2986 COCOA_LOG_FLOW(("cocoaViewShow: pView=%p fShowIt=%d\n", (void *)pView, fShowIt));
2987 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
2988
2989 [(OverlayView *)pView vboxSetVisible:fShowIt];
2990
2991 [pPool release];
2992 COCOA_LOG_FLOW(("cocoaViewShow: returns\n"));
2993}
2994
2995void cocoaViewDisplay(NativeNSViewRef pView)
2996{
2997 COCOA_LOG_FLOW(("cocoaViewDisplay: pView=%p\n", (void *)pView));
2998 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
2999
3000#ifndef IN_VMSVGA3D
3001 DEBUG_WARN(("cocoaViewDisplay should never happen!\n"));
3002 DEBUG_MSG_1(("cocoaViewDisplay %p\n", (void *)pView));
3003#endif
3004 [(OverlayView *)pView swapFBO];
3005
3006 [pPool release];
3007 COCOA_LOG_FLOW(("cocoaViewDisplay: returns\n"));
3008}
3009
3010void cocoaViewSetPosition(NativeNSViewRef pView, NativeNSViewRef pParentView, int x, int y)
3011{
3012 COCOA_LOG_FLOW(("cocoaViewSetPosition: pView=%p pParentView=%p x=%d y=%d\n", (void *)pView, (void *)pParentView, x, y));
3013 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
3014
3015 [(OverlayView *)pView vboxSetPos:NSMakePoint(x, y)];
3016
3017 [pPool release];
3018 COCOA_LOG_FLOW(("cocoaViewSetPosition: returns\n"));
3019}
3020
3021void cocoaViewSetSize(NativeNSViewRef pView, int cx, int cy)
3022{
3023 COCOA_LOG_FLOW(("cocoaViewSetSize: pView=%p cx=%d cy=%d\n", (void *)pView, cx, cy));
3024 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
3025
3026 [(OverlayView *)pView vboxSetSize:NSMakeSize(cx, cy)];
3027
3028 [pPool release];
3029 COCOA_LOG_FLOW(("cocoaViewSetSize: returns\n"));
3030}
3031
3032#ifndef IN_VMSVGA3D
3033
3034typedef struct CR_RCD_GETGEOMETRY
3035{
3036 OverlayView *pView;
3037 NSRect rect;
3038} CR_RCD_GETGEOMETRY;
3039
3040static DECLCALLBACK(void) vboxRcdGetGeomerty(void *pvUser)
3041{
3042 CR_RCD_GETGEOMETRY *pGetGeometry = (CR_RCD_GETGEOMETRY *)pvUser;
3043 pGetGeometry->rect = [[pGetGeometry->pView window] frame];
3044 COCOA_LOG_FLOW(("vboxRcdGetGeomerty: (x,y)=(%d,%d) (cx,cy)=(%d,%d)\n", pGetGeometry->rect.origin.x, pGetGeometry->rect.origin.y,
3045 pGetGeometry->rect.size.width, pGetGeometry->rect.size.height));
3046}
3047
3048#endif /* !IN_VMSVGA3D */
3049
3050void cocoaViewGetGeometry(NativeNSViewRef pView, int *px, int *py, int *pcx, int *pcy)
3051{
3052 COCOA_LOG_FLOW(("cocoaViewGetGeometry: pView=%p px=%p py=%p pcx=%p pcy=%p\n",
3053 (void *)pView, (void *)px, (void *)py, (void *)pcx, (void *)pcy));
3054 NSAutoreleasePool *pPool;
3055 pPool = [[NSAutoreleasePool alloc] init];
3056
3057 /* make sure all tasks are run, to preserve the order */
3058 VBoxMainThreadTaskRunner *pRunner = [VBoxMainThreadTaskRunner globalInstance];
3059 [pRunner runTasksSyncIfPossible];
3060
3061 NSRect frame;
3062#ifndef IN_VMSVGA3D
3063 if (renderspuCalloutAvailable())
3064 {
3065 CR_RCD_GETGEOMETRY GetGeometry;
3066 GetGeometry.pView = (OverlayView *)pView;
3067 renderspuCalloutClient(vboxRcdGetGeomerty, &GetGeometry);
3068 frame = GetGeometry.rect;
3069 }
3070 else
3071#endif
3072 {
3073 DEBUG_MSG_NOT_VMSVGA3D(("no callout available on getGeometry\n"));
3074 frame = [[pView window] frame];
3075 }
3076
3077 *px = frame.origin.x;
3078 *py = frame.origin.y;
3079 *pcx = frame.size.width;
3080 *pcy = frame.size.height;
3081
3082 [pPool release];
3083 COCOA_LOG_FLOW(("cocoaViewGetGeometry: returns *px=%d, *py=%d, *pcx=%d, *pcy=%d\n", *px, *py, *pcx, *pcy));
3084}
3085
3086void cocoaViewPresentComposition(NativeNSViewRef pView, PCVBOXVR_SCR_COMPOSITOR_ENTRY pChangedEntry)
3087{
3088 COCOA_LOG_FLOW(("cocoaViewPresentComposition: pView=%p pChangedEntry=%p\n", (void *)pView, (void *)pChangedEntry));
3089 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
3090 NSOpenGLContext *pCtx;
3091
3092 /* view should not necesserily have a context set */
3093 pCtx = [(OverlayView *)pView glCtx];
3094 if (!pCtx)
3095 {
3096#ifdef IN_VMSVGA3D /** @todo VMSVGA3 */
3097 pCtx = NULL;
3098#else
3099 ContextInfo *pCtxInfo = renderspuDefaultSharedContextAcquire();
3100 if (!pCtxInfo)
3101 {
3102 DEBUG_WARN(("renderspuDefaultSharedContextAcquire returned NULL"));
3103
3104 [pPool release];
3105 DEBUG_FUNC_LEAVE();
3106 return;
3107 }
3108
3109 pCtx = pCtxInfo->context;
3110#endif
3111
3112 [(OverlayView *)pView setGLCtx:pCtx];
3113 }
3114
3115 [(OverlayView *)pView presentComposition:pChangedEntry];
3116
3117 [pPool release];
3118 COCOA_LOG_FLOW(("cocoaViewPresentComposition: returns\n"));
3119}
3120
3121void cocoaViewMakeCurrentContext(NativeNSViewRef pView, NativeNSOpenGLContextRef pCtx)
3122{
3123 COCOA_LOG_FLOW(("cocoaViewMakeCurrentContext: pView=%p pCtx=%p\n", (void *)pView, (void *)pCtx));
3124 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
3125
3126 if (pView)
3127 {
3128 [(OverlayView *)pView setGLCtx:pCtx];
3129 [(OverlayView *)pView makeCurrentFBO];
3130 }
3131 else
3132 {
3133 [NSOpenGLContext clearCurrentContext];
3134 }
3135
3136 [pPool release];
3137 COCOA_LOG_FLOW(("cocoaViewMakeCurrentContext: returns\n"));
3138}
3139
3140GLboolean cocoaViewNeedsEmptyPresent(NativeNSViewRef pView)
3141{
3142 COCOA_LOG_FLOW(("cocoaViewNeedsEmptyPresent: pView=%p\n", (void *)pView));
3143 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
3144
3145 GLboolean fNeedsPresent = [(OverlayView *)pView vboxNeedsEmptyPresent];
3146
3147 [pPool release];
3148 COCOA_LOG_FLOW(("cocoaViewNeedsEmptyPresent: returns %d\n", fNeedsPresent));
3149 return fNeedsPresent;
3150}
3151
3152void cocoaViewSetVisibleRegion(NativeNSViewRef pView, GLint cRects, const GLint *paRects)
3153{
3154 COCOA_LOG_FLOW(("cocoaViewSetVisibleRegion: pView=%p cRects=%d paRects=%p)\n", (void *)pView, cRects, (void const *)paRects));
3155 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
3156
3157 [(OverlayView *)pView setVisibleRegions:cRects paRects:paRects];
3158
3159 [pPool release];
3160 COCOA_LOG_FLOW(("cocoaViewSetVisibleRegion: returns\n"));
3161}
3162
3163
3164#ifdef IN_VMSVGA3D
3165/*
3166 * VMSVGA3D interface.
3167 */
3168
3169VMSVGA3D_DECL(void) vmsvga3dCocoaCreateContext(NativeNSOpenGLContextRef *ppCtx, NativeNSOpenGLContextRef pSharedCtx,
3170 bool fOtherProfile)
3171{
3172 cocoaGLCtxCreate(ppCtx, CR_ALPHA_BIT | CR_DEPTH_BIT | CR_DOUBLE_BIT | (fOtherProfile ? VMSVGA3D_NON_DEFAULT_PROFILE_BIT : 0),
3173 pSharedCtx);
3174}
3175
3176VMSVGA3D_DECL(void) vmsvga3dCocoaDestroyContext(NativeNSOpenGLContextRef pCtx)
3177{
3178 cocoaGLCtxDestroy(pCtx);
3179}
3180
3181VMSVGA3D_DECL(void) vmsvga3dCocoaCreateView(NativeNSViewRef *ppView, NativeNSViewRef pParentView)
3182{
3183 /** @todo share WinInfo with caller and maintain it better. */
3184 WindowInfo *pWinInfo = (WindowInfo *)RTMemAllocZ(sizeof(WindowInfo));
3185 AssertLogRelReturnVoid(pWinInfo);
3186 pWinInfo->cRefs = 1;
3187 RTCritSectInit(&pWinInfo->CompositorLock);
3188
3189 cocoaViewCreate(ppView, pWinInfo, pParentView, 0 /* fVisParams - ignored */);
3190}
3191
3192VMSVGA3D_DECL(void) vmsvga3dCocoaDestroyView(NativeNSViewRef pView)
3193{
3194 cocoaViewDestroy(pView);
3195}
3196
3197VMSVGA3D_DECL(void) vmsvga3dCocoaViewSetPosition(NativeNSViewRef pView, NativeNSViewRef pParentView, int x, int y)
3198{
3199 cocoaViewSetPosition(pView, pParentView, x, y);
3200}
3201
3202VMSVGA3D_DECL(void) vmsvga3dCocoaViewSetSize(NativeNSViewRef pView, int w, int h)
3203{
3204 cocoaViewSetSize(pView, w, h);
3205}
3206
3207VMSVGA3D_DECL(void) vmsvga3dCocoaViewMakeCurrentContext(NativeNSViewRef pView, NativeNSOpenGLContextRef pCtx)
3208{
3209 cocoaViewMakeCurrentContext(pView, pCtx);
3210}
3211
3212VMSVGA3D_DECL(void) vmsvga3dCocoaSwapBuffers(NativeNSViewRef pView, NativeNSOpenGLContextRef pCtx)
3213{
3214# if 1
3215 Assert([(OverlayView *)pView glCtx] == pCtx);
3216 cocoaViewDisplay(pView);
3217# else
3218 DEBUG_FUNC_ENTER();
3219 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
3220
3221 [pCtx flushBuffer];
3222
3223 [pPool release];
3224 DEBUG_FUNC_LEAVE();
3225# endif
3226}
3227
3228#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