VirtualBox

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

最後變更 在這個檔案從54668是 54638,由 vboxsync 提交於 10 年 前

Looks like we have to do glFlush() before changing GL context on mac os x.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 101.5 KB
 
1/* $Id: renderspu_cocoa_helper.m 54638 2015-03-05 00:33:47Z 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.alldomusa.eu.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 VBOX_STRICT
196# define DEBUG_CLEAR_GL_ERRORS() \
197 do { \
198 while (glGetError() != GL_NO_ERROR) \
199 { /* nothing */ } \
200 } while (0)
201# define DEBUG_CHECK_GL_ERROR(a_szOp) \
202 do { \
203 GLenum iGlCheckErr = glGetError(); \
204 if (RT_UNLIKELY(iGlCheckErr != GL_NO_ERROR)) \
205 AssertMsgFailed((a_szOp ": iGlCheckErr=%#x\n", iGlCheckErr)); \
206 } while (0)
207#else
208# define DEBUG_CLEAR_GL_ERRORS() do {} while (0)
209# define DEBUG_CHECK_GL_ERROR(a_szOp) do {} while (0)
210#endif
211
212/* Whether we control NSView automatic content zooming on Retina/HiDPI displays. */
213#define VBOX_WITH_CONFIGURABLE_HIDPI_SCALING 1
214
215#ifdef IN_VMSVGA3D
216
217/*
218 * VMSVGA3D compatibility glue.
219 */
220
221# define CR_RGB_BIT RT_BIT_32(0)
222
223# define CR_ALPHA_BIT RT_BIT_32(1)
224# define CR_DEPTH_BIT RT_BIT_32(2)
225# define CR_STENCIL_BIT RT_BIT_32(3)
226# define CR_ACCUM_BIT RT_BIT_32(4)
227# define CR_DOUBLE_BIT RT_BIT_32(5)
228# define CR_STEREO_BIT RT_BIT_32(6)
229# define CR_MULTISAMPLE_BIT RT_BIT_32(7)
230
231# define CR_OVERLAY_BIT RT_BIT_32(8)
232# define CR_PBUFFER_BIT RT_BIT_32(9)
233# define VMSVGA3D_NON_DEFAULT_PROFILE_BIT RT_BIT_32(31)
234# define CR_ALL_BITS UINT32_C(0x800003ff)
235
236typedef struct WindowInfo
237{
238 uint32_t volatile cRefs;
239 RTCRITSECT CompositorLock;
240 PCVBOXVR_SCR_COMPOSITOR pCompositor;
241
242 //NativeNSViewRef window;
243 //NativeNSViewRef nativeWindow; /**< for render_to_app_window */
244 NativeNSOpenGLContextRef *currentCtx;
245} WindowInfo;
246
247static void vmsvga3DWinInfoDestroy(WindowInfo *pWinInfo)
248{
249 /** @todo */
250}
251
252DECLINLINE(void) renderspuWinRetain(WindowInfo *pWinInfo)
253{
254 ASMAtomicIncU32(&pWinInfo->cRefs);
255}
256
257DECLINLINE(void) renderspuWinRelease(WindowInfo *pWinInfo)
258{
259 uint32_t cRefs = ASMAtomicDecU32(&pWinInfo->cRefs);
260 if (!cRefs)
261 vmsvga3DWinInfoDestroy(pWinInfo);
262}
263
264static int renderspuVBoxCompositorLock(WindowInfo *pWinInfo, PCVBOXVR_SCR_COMPOSITOR *ppCompositor)
265{
266 int rc = RTCritSectEnter(&pWinInfo->CompositorLock);
267 AssertRCReturn(rc, rc);
268 if (ppCompositor)
269 *ppCompositor = pWinInfo->pCompositor;
270 return VINF_SUCCESS;
271}
272
273static int renderspuVBoxCompositorUnlock(WindowInfo *pWinInfo)
274{
275 int rc = RTCritSectLeave(&pWinInfo->CompositorLock);
276 AssertRC(rc);
277 return rc;
278}
279
280static PCVBOXVR_SCR_COMPOSITOR renderspuVBoxCompositorAcquire(WindowInfo *pWinInfo)
281{
282 int rc = RTCritSectEnter(&pWinInfo->CompositorLock);
283 AssertRCReturn(rc, NULL);
284
285 PCVBOXVR_SCR_COMPOSITOR pCompositor = pWinInfo->pCompositor;
286 if (pCompositor)
287 {
288 Assert(!CrVrScrCompositorIsEmpty(pWinInfo->pCompositor));
289 return pCompositor;
290 }
291
292 /* if no compositor is set, release the lock and return */
293 RTCritSectLeave(&pWinInfo->CompositorLock);
294 return NULL;
295}
296
297static void renderspuVBoxCompositorRelease(WindowInfo *pWinInfo)
298{
299 Assert(pWinInfo->pCompositor);
300 Assert(!CrVrScrCompositorIsEmpty(pWinInfo->pCompositor));
301 int rc = RTCritSectLeave(&pWinInfo->CompositorLock);
302 AssertRC(rc);
303}
304
305
306#endif /* IN_VMSVGA3D */
307
308
309
310static NSOpenGLContext *vboxCtxGetCurrent(void)
311{
312#ifdef IN_VMSVGA3D
313 return [NSOpenGLContext currentContext];
314#else
315 GET_CONTEXT(pCtxInfo);
316 if (pCtxInfo)
317 {
318 Assert(pCtxInfo->context);
319 return pCtxInfo->context;
320 }
321 return nil;
322#endif
323}
324
325static bool vboxCtxSyncCurrentInfo(void)
326{
327#ifdef IN_VMSVGA3D
328 return false;
329#else
330 bool fAdjusted = false;
331 GET_CONTEXT(pCtxInfo);
332 NSOpenGLContext *pCtx = [NSOpenGLContext currentContext];
333 NSView *pView = pCtx ? [pCtx view] : nil;
334 if (pCtxInfo)
335 {
336 WindowInfo *pWinInfo = pCtxInfo->currentWindow;
337 Assert(pWinInfo);
338 if ( pCtxInfo->context != pCtx
339 || pWinInfo->window != pView)
340 {
341 renderspu_SystemMakeCurrent(pWinInfo, 0, pCtxInfo);
342 fAdjusted = true;
343 }
344 }
345 else if (pCtx)
346 {
347 [NSOpenGLContext clearCurrentContext];
348 fAdjusted = true;
349 }
350
351 return fAdjusted;
352#endif
353}
354
355
356/**
357 * State carrying structure for use with vboxCtxEnter and vboxCtxLeave
358 */
359typedef struct VBOX_CR_RENDER_CTX_INFO
360{
361 bool fIsValid;
362 NSOpenGLContext *pCtx;
363 NSView *pView;
364} VBOX_CR_RENDER_CTX_INFO;
365/** Pointer to render context info for use with vboxCtxEnter/Leave. */
366typedef VBOX_CR_RENDER_CTX_INFO *PVBOX_CR_RENDER_CTX_INFO;
367
368static void vboxCtxEnter(NSOpenGLContext *pNewCtx, PVBOX_CR_RENDER_CTX_INFO pCtxInfo)
369{
370 NSOpenGLContext *pOldCtx = vboxCtxGetCurrent();
371 NSView *pOldView = pOldCtx ? [pOldCtx view] : nil;
372 NSView *pNewView = [pNewCtx view];
373
374 Assert(pNewCtx);
375
376 if ( pOldCtx != pNewCtx
377 || pOldView != pNewView)
378 {
379 if (pOldCtx != nil)
380 glFlush();
381
382 DEBUG_CLEAR_GL_ERRORS();
383 [pNewCtx makeCurrentContext];
384 DEBUG_CHECK_GL_ERROR("makeCurrentContext");
385
386 pCtxInfo->fIsValid = true;
387 pCtxInfo->pCtx = pOldCtx;
388 /** @todo r=bird: Why do we save the NEW VIEW here? vboxCtxLeave calls it 'pOldView'. Bug? */
389 pCtxInfo->pView = pNewView;
390 }
391 else
392 {
393 /* No context switch necessary. */
394 pCtxInfo->fIsValid = false;
395 }
396}
397
398static void vboxCtxLeave(PVBOX_CR_RENDER_CTX_INFO pCtxInfo)
399{
400 if (pCtxInfo->fIsValid)
401 {
402 NSOpenGLContext *pOldCtx = pCtxInfo->pCtx;
403 NSView *pOldView = pCtxInfo->pView;
404
405 glFlush();
406 if (pOldCtx != nil)
407 {
408 /* vboxCtxEnter saves the new view, not the old. So, what we actually
409 do here is switching the view of the old context to that of the new
410 one (wrt vboxCtxEnter) before making it current. */
411 /** @todo r=bird: Figure out what we really want to do here, and either rename
412 * pOldView or fix the code. */
413 if ([pOldCtx view] != pOldView)
414 {
415 DEBUG_CLEAR_GL_ERRORS();
416 [pOldCtx setView: pOldView];
417 DEBUG_CHECK_GL_ERROR("setView");
418 }
419
420 DEBUG_CLEAR_GL_ERRORS();
421 [pOldCtx makeCurrentContext];
422 DEBUG_CHECK_GL_ERROR("makeCurrentContext");
423
424#ifdef VBOX_STRICT
425 {
426 NSOpenGLContext *pTstOldCtx = [NSOpenGLContext currentContext];
427 NSView *pTstOldView = pTstOldCtx ? [pTstOldCtx view] : nil;
428 Assert(pTstOldCtx == pOldCtx);
429 Assert(pTstOldView == pOldView);
430 }
431#endif
432 }
433 else
434 {
435 [NSOpenGLContext clearCurrentContext];
436 }
437 }
438}
439
440
441/**
442 * Custom OpenGL context class.
443 *
444 * This implementation doesn't allow to set a view to the context, but save the
445 * view for later use. Also it saves a copy of the pixel format used to create
446 * that context for later use.
447 */
448@interface OverlayOpenGLContext: NSOpenGLContext
449{
450@private
451 NSOpenGLPixelFormat *m_pPixelFormat;
452 NSView *m_pView;
453}
454- (NSOpenGLPixelFormat *)openGLPixelFormat;
455@end
456
457/**
458 * Abstrack task class.
459 */
460@interface VBoxTask : NSObject
461{
462}
463- (void)run;
464@end
465
466@implementation VBoxTask
467/** Run method that the child classes must reimplement.
468 * This will abort the process. */
469- (void)run
470{
471 AssertReleaseFailed();
472}
473@end
474
475
476/**
477 * Generic task class for executing a given method select.
478 */
479@interface VBoxTaskPerformSelector : VBoxTask
480{
481@private
482 id m_Object;
483 SEL m_Selector;
484 id m_Arg;
485}
486- (id)initWithObject:(id)aObject selector:(SEL)aSelector arg:(id)aArg;
487- (void)run;
488- (void)dealloc;
489@end
490
491@implementation VBoxTaskPerformSelector
492
493/**
494 * Initializes a VBoxTaskPerformSelector.
495 *
496 * @param aObject The object (reference not consumed).
497 * @param aSelector The method selector.
498 * @param aArg The method argument (reference not consumed).
499 */
500- (id)initWithObject:(id)aObject selector:(SEL)aSelector arg:(id)aArg
501{
502 self = [super init];
503 if (self)
504 {
505 [aObject retain];
506 m_Object = aObject;
507 m_Selector = aSelector;
508 if (aArg != nil)
509 [aArg retain];
510 m_Arg = aArg;
511 }
512
513 return self;
514}
515
516- (void)run
517{
518 [m_Object performSelector:m_Selector withObject:m_Arg];
519}
520
521- (void)dealloc
522{
523 [m_Object release];
524 if (m_Arg != nil)
525 [m_Arg release];
526
527 [super dealloc];
528}
529@end
530
531
532/**
533 *
534 */
535@interface VBoxTaskComposite : VBoxTask
536{
537@private
538 NSUInteger m_CurIndex;
539 RTCRITSECT m_Lock;
540 NSMutableArray *m_pArray;
541}
542- (id)init;
543- (void)add:(VBoxTask *)pTask;
544- (void)run;
545- (void)dealloc;
546@end
547
548@implementation VBoxTaskComposite
549- (id)init
550{
551 self = [super init];
552
553 if (self)
554 {
555 int rc = RTCritSectInit(&m_Lock);
556 if (!RT_SUCCESS(rc))
557 {
558 DEBUG_WARN(("RTCritSectInit failed %d\n", rc));
559 return nil;
560 }
561
562 m_CurIndex = 0;
563
564 m_pArray = [[NSMutableArray alloc] init];
565 }
566
567 return self;
568}
569
570/**
571 * Adds a task to the composite task object.
572 *
573 * @param pTask Task to add. Reference is NOT consumed.
574 */
575- (void)add:(VBoxTask *)pTask
576{
577 [pTask retain];
578 int rc = RTCritSectEnter(&m_Lock);
579 if (RT_SUCCESS(rc))
580 {
581 [m_pArray addObject:pTask];
582 RTCritSectLeave(&m_Lock);
583 }
584 else
585 {
586 DEBUG_WARN(("RTCritSectEnter failed %d\n", rc));
587 [pTask release];
588 }
589}
590
591- (void)run
592{
593 for (;;)
594 {
595 /*
596 * Dequeue a task.
597 */
598 int rc = RTCritSectEnter(&m_Lock);
599 if (RT_FAILURE(rc))
600 {
601 DEBUG_WARN(("RTCritSectEnter failed %d\n", rc));
602 break;
603 }
604
605 NSUInteger count = [m_pArray count];
606 Assert(m_CurIndex <= count);
607 if (m_CurIndex == count)
608 {
609 [m_pArray removeAllObjects];
610 m_CurIndex = 0;
611 RTCritSectLeave(&m_Lock);
612 break;
613 }
614
615 VBoxTask *pTask = (VBoxTask *)[m_pArray objectAtIndex:m_CurIndex];
616 Assert(pTask != nil);
617
618 ++m_CurIndex;
619
620 /*
621 * Remove the first 1025 empty entires.
622 */
623 if (m_CurIndex > 1024)
624 {
625 NSRange range;
626 range.location = 0;
627 range.length = m_CurIndex;
628 [m_pArray removeObjectsInRange:range];
629 m_CurIndex = 0;
630 }
631 RTCritSectLeave(&m_Lock);
632
633 /*
634 * Run the task and release it.
635 */
636 [pTask run];
637 [pTask release];
638 }
639}
640
641- (void)dealloc
642{
643 NSUInteger count = [m_pArray count];
644 for (;m_CurIndex < count; ++m_CurIndex)
645 {
646 VBoxTask *pTask = (VBoxTask*)[m_pArray objectAtIndex:m_CurIndex];
647 DEBUG_WARN(("dealloc with non-empty tasks! %p\n", pTask));
648 [pTask release];
649 }
650
651 [m_pArray release];
652 RTCritSectDelete(&m_Lock);
653
654 [super dealloc];
655}
656@end
657
658
659/**
660 *
661 *
662 */
663@interface VBoxMainThreadTaskRunner : NSObject
664{
665@private
666 VBoxTaskComposite *m_pTasks;
667}
668- (id)init;
669- (void)add:(VBoxTask *)pTask;
670- (void)addObj:(id)aObject selector:(SEL)aSelector arg:(id)aArg;
671- (void)runTasks;
672- (bool)runTasksSyncIfPossible;
673- (void)dealloc;
674+ (VBoxMainThreadTaskRunner *) globalInstance;
675@end
676
677@implementation VBoxMainThreadTaskRunner
678- (id)init
679{
680 self = [super init];
681 if (self)
682 {
683 m_pTasks = [[VBoxTaskComposite alloc] init];
684 }
685
686 return self;
687}
688
689+ (VBoxMainThreadTaskRunner *) globalInstance
690{
691 static dispatch_once_t s_DispatchOnce;
692 static VBoxMainThreadTaskRunner *s_pRunner = nil;
693 dispatch_once(&s_DispatchOnce, ^{
694 s_pRunner = [[VBoxMainThreadTaskRunner alloc] init];
695 });
696 return s_pRunner;
697}
698
699- (void)add:(VBoxTask *)pTask
700{
701 DEBUG_FUNC_ENTER();
702 [m_pTasks add:pTask];
703 /** @todo r=bird: Unbalanced [self retain]. */
704 [self retain];
705
706 if (![self runTasksSyncIfPossible])
707 {
708 DEBUG_MSG(("task will be processed async\n"));
709 [self performSelectorOnMainThread:@selector(runTasks) withObject:nil waitUntilDone:NO];
710 }
711
712 DEBUG_FUNC_LEAVE();
713}
714
715/**
716 * Adds a task calling an object method (selector).
717 *
718 * @param aObject The object (reference not consumed)..
719 * @param aSelector The method selector.
720 * @param aArg The method argument (reference not consumed).
721 */
722- (void)addObj:(id)aObject selector:(SEL)aSelector arg:(id)aArg
723{
724 VBoxTaskPerformSelector *pSelTask = [[VBoxTaskPerformSelector alloc] initWithObject:aObject selector:aSelector arg:aArg];
725 [self add:pSelTask];
726 [pSelTask release];
727}
728
729
730/**
731 * Internal method for running the pending tasks.
732 */
733- (void)runTasks
734{
735 if ([NSThread isMainThread])
736 {
737 [m_pTasks run];
738 /** @todo r=bird: This release and the retain in the add method aren't
739 * necessarily balanced if there are more than one call to add().
740 *
741 * This could probably end up deleting the singleton prematurely and leave
742 * globalInstance() returning pointers to a stale object in freed memory,
743 * quite possibly causing crashes or/and heap corruption. */
744 [self release];
745 }
746 else
747 {
748 DEBUG_WARN(("run tasks called not on main thread!\n"));
749#ifndef DEBUG_VERBOSE
750 AssertFailed();
751#endif
752 [self performSelectorOnMainThread:@selector(runTasks) withObject:nil waitUntilDone:YES];
753 }
754}
755
756/**
757 * Callback for calling runTasks via renderspuCalloutClient.
758 * @param pvUser The VBoxMainThreadTaskRunner singleton.
759 */
760static DECLCALLBACK(void) VBoxMainThreadTaskRunner_RcdRunCallback(void *pvUser)
761{
762 DEBUG_FUNC_ENTER();
763 VBoxMainThreadTaskRunner *pRunner = (VBoxMainThreadTaskRunner *)pvUser;
764 Assert(pRunner == [VBoxMainThreadTaskRunner globalInstance]);
765 [pRunner runTasks];
766 DEBUG_FUNC_LEAVE();
767}
768
769/**
770 * Runs pending tasks synchronously, if possible in the current context.
771 *
772 * @returns true if executed tasks, false if not possible.
773 */
774- (bool)runTasksSyncIfPossible
775{
776#ifndef IN_VMSVGA3D
777 /*
778 * Call on main thread (?) via renderspuCalloutClient (whatever that is).
779 */
780 if (renderspuCalloutAvailable())
781 {
782 Assert(![NSThread isMainThread]);
783 renderspuCalloutClient(VBoxMainThreadTaskRunner_RcdRunCallback, self);
784 return true;
785 }
786#endif
787
788 /*
789 * Run directly if on main thread.
790 */
791 if ([NSThread isMainThread])
792 {
793 [self runTasks];
794 return true;
795 }
796
797 /* Not possible. */
798 return false;
799}
800
801- (void)dealloc
802{
803 /** @todo r=bird: WTF is the point of the deallocator. The object is a singelton
804 * stored in an inaccessible static variable! */
805 [m_pTasks release];
806 m_pTasks = nil;
807
808 [super dealloc];
809}
810
811@end
812
813@class DockOverlayView;
814
815/**
816 * The custom view class.
817 *
818 * This is the main class of the cocoa OpenGL implementation. It manages a
819 * frame buffer object for the rendering of the guest applications. The guest
820 * applications render in this frame buffer which is bound to an OpenGL texture.
821 * To display the guest content, a secondary shared OpenGL context of the main
822 * OpenGL context is created. The secondary context is marked as non-opaque and
823 * the texture is displayed on an object which is composed out of the several
824 * visible region rectangles.
825 */
826@interface OverlayView : NSView
827{
828@private
829 NSView *m_pParentView;
830 NSWindow *m_pOverlayWin;
831
832 NSOpenGLContext *m_pGLCtx;
833 NSOpenGLContext *m_pSharedGLCtx;
834 RTTHREAD m_Thread;
835
836 GLuint m_FBOId;
837
838 /** The corresponding dock tile view of this OpenGL view & all helper
839 * members. */
840 DockOverlayView *m_DockTileView;
841
842 GLfloat m_FBOThumbScaleX;
843 GLfloat m_FBOThumbScaleY;
844 uint64_t m_msDockUpdateTS;
845
846 /** @name For clipping
847 * @remarks appears to be unused and a complete waste of time + heap.
848 * @{ */
849 GLint m_cClipRects;
850 GLint *m_paClipRects;
851 /** @} */
852
853 /** @name Position/Size tracking
854 * @{ */
855 NSPoint m_Pos;
856 NSSize m_Size;
857 /** @} */
858
859 /** This is necessary for clipping on the root window */
860 NSRect m_RootRect;
861 float m_yInvRootOffset;
862
863 CR_BLITTER *m_pBlitter;
864 WindowInfo *m_pWinInfo;
865 bool m_fNeedViewportUpdate;
866 bool m_fNeedCtxUpdate;
867 bool m_fDataVisible;
868 bool m_fCleanupNeeded;
869 bool m_fEverSized;
870}
871- (id)initWithFrame:(NSRect)frame thread:(RTTHREAD)aThread parentView:(NSView *)pParentView winInfo:(WindowInfo *)pWinInfo;
872- (void)setGLCtx:(NSOpenGLContext*)pCtx;
873- (NSOpenGLContext *)glCtx;
874
875- (void)setParentView: (NSView *)view;
876- (NSView *)parentView;
877- (void)setOverlayWin: (NSWindow *)win;
878- (NSWindow *)overlayWin;
879
880- (void)vboxSetPos:(NSPoint)pos;
881- (void)vboxSetPosUI:(NSPoint)pos;
882- (void)vboxSetPosUIObj:(NSValue *)pPos;
883- (NSPoint)pos;
884- (bool)isEverSized;
885- (void)vboxDestroy;
886- (void)vboxSetSizeUI:(NSSize)size;
887- (void)vboxSetSizeUIObj:(NSValue *)pSize;
888- (void)vboxSetSize:(NSSize)size;
889- (NSSize)size;
890- (void)updateViewportCS;
891#ifdef VBOX_WITH_CONFIGURABLE_HIDPI_SCALING
892- (NSRect)safeConvertRectToBacking:(NSRect *)pRect;
893- (CGFloat)safeGetBackingScaleFactor;
894#endif
895- (NSRect)safeConvertToScreen:(NSRect *)pRect;
896- (void)vboxReshapePerform;
897- (void)vboxReshapeOnResizePerform;
898- (void)vboxReshapeOnReparentPerform;
899
900- (void)createDockTile;
901- (void)deleteDockTile;
902
903- (void)makeCurrentFBO;
904- (void)swapFBO;
905- (void)vboxSetVisible:(GLboolean)fVisible;
906- (void)vboxSetVisibleUIObj:(NSNumber *)pVisible;
907- (void)vboxSetVisibleUI:(GLboolean)fVisible;
908- (void)vboxTryDraw;
909- (void)vboxTryDrawUI;
910- (void)vboxReparent:(NSView *)pParentView;
911- (void)vboxReparentUI:(NSView *)pParentView;
912- (void)vboxPresent:(const VBOXVR_SCR_COMPOSITOR *)pCompositor;
913- (void)vboxPresentCS:(const VBOXVR_SCR_COMPOSITOR *)pCompositor;
914- (void)vboxPresentToDockTileCS:(const VBOXVR_SCR_COMPOSITOR *)pCompositor;
915- (void)vboxPresentToViewCS:(const VBOXVR_SCR_COMPOSITOR *)pCompositor;
916- (void)presentComposition:(const VBOXVR_SCR_COMPOSITOR_ENTRY *)pChangedEntry;
917- (void)vboxBlitterSyncWindow;
918
919- (void)clearVisibleRegions;
920- (void)setVisibleRegions:(GLint)cRects paRects:(const GLint *)paRects;
921- (GLboolean)vboxNeedsEmptyPresent;
922
923- (NSView *)dockTileScreen;
924- (void)reshapeDockTile;
925- (void)cleanupData;
926@end
927
928/**
929 * Helper view.
930 *
931 * This view is added as a sub view of the parent view to track
932 * main window changes. Whenever the main window is changed
933 * (which happens on fullscreen/seamless entry/exit) the overlay
934 * window is informed & can add them self as a child window
935 * again.
936 */
937@class OverlayWindow;
938@interface OverlayHelperView: NSView
939{
940@private
941 OverlayWindow *m_pOverlayWindow;
942}
943-(id)initWithOverlayWindow:(OverlayWindow *)pOverlayWindow;
944@end
945
946/**
947 * Custom window class.
948 *
949 * This is the overlay window which contains our custom NSView.
950 * Its a direct child of the Qt Main window. It marks its background
951 * transparent & non opaque to make clipping possible. It also disable mouse
952 * events and handle frame change events of the parent view.
953 */
954@interface OverlayWindow : NSWindow
955{
956@private
957 NSView *m_pParentView;
958 OverlayView *m_pOverlayView;
959 OverlayHelperView *m_pOverlayHelperView;
960 NSThread *m_Thread;
961}
962- (id)initWithParentView:(NSView *)pParentView overlayView:(OverlayView *)pOverlayView;
963- (void)parentWindowFrameChanged:(NSNotification *)note;
964- (void)parentWindowChanged:(NSWindow *)pWindow;
965@end
966
967
968/**
969 * Dock overlay view class.
970 */
971@interface DockOverlayView: NSView
972{
973 NSBitmapImageRep *m_ThumbBitmap;
974 NSImage *m_ThumbImage;
975 NSLock *m_Lock;
976}
977- (void)dealloc;
978- (void)cleanup;
979- (void)lock;
980- (void)unlock;
981- (void)setFrame:(NSRect)frame;
982- (void)drawRect:(NSRect)aRect;
983- (NSBitmapImageRep *)thumbBitmap;
984- (NSImage *)thumbImage;
985@end
986
987@implementation DockOverlayView
988- (id)init
989{
990 DEBUG_FUNC_ENTER();
991 self = [super init];
992 if (self)
993 {
994 /*
995 * We need a lock cause the thumb image could be accessed from the main
996 * thread when someone is calling display on the dock tile & from the
997 * OpenGL thread when the thumbnail is updated.
998 */
999 m_Lock = [[NSLock alloc] init];
1000 }
1001
1002 DEBUG_FUNC_LEAVE();
1003
1004 return self;
1005}
1006
1007- (void)dealloc
1008{
1009 DEBUG_FUNC_ENTER();
1010
1011 [self cleanup];
1012 [m_Lock release];
1013
1014 [super dealloc];
1015
1016 DEBUG_FUNC_LEAVE();
1017}
1018
1019- (void)cleanup
1020{
1021 DEBUG_FUNC_ENTER();
1022
1023 if (m_ThumbImage != nil)
1024 {
1025 [m_ThumbImage release];
1026 m_ThumbImage = nil;
1027 }
1028
1029 if (m_ThumbBitmap != nil)
1030 {
1031 [m_ThumbBitmap release];
1032 m_ThumbBitmap = nil;
1033 }
1034
1035 DEBUG_FUNC_LEAVE();
1036}
1037
1038- (void)lock
1039{
1040 DEBUG_FUNC_ENTER();
1041 [m_Lock lock];
1042 DEBUG_FUNC_LEAVE();
1043}
1044
1045- (void)unlock
1046{
1047 DEBUG_FUNC_ENTER();
1048 [m_Lock unlock];
1049 DEBUG_FUNC_LEAVE();
1050}
1051
1052- (void)setFrame:(NSRect)frame
1053{
1054 DEBUG_FUNC_ENTER();
1055 [super setFrame:frame];
1056
1057 [self lock];
1058 [self cleanup];
1059
1060 if ( frame.size.width > 0
1061 && frame.size.height > 0)
1062 {
1063 /* Create a buffer for our thumbnail image. Its in the size of this view. */
1064 m_ThumbBitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
1065 pixelsWide:frame.size.width
1066 pixelsHigh:frame.size.height
1067 bitsPerSample:8
1068 samplesPerPixel:4
1069 hasAlpha:YES
1070 isPlanar:NO
1071 colorSpaceName:NSDeviceRGBColorSpace
1072 bitmapFormat:NSAlphaFirstBitmapFormat
1073 bytesPerRow:frame.size.width * 4
1074 bitsPerPixel:8 * 4
1075 ];
1076 m_ThumbImage = [[NSImage alloc] initWithSize:[m_ThumbBitmap size]];
1077 [m_ThumbImage addRepresentation:m_ThumbBitmap];
1078 }
1079
1080 [self unlock];
1081 DEBUG_FUNC_LEAVE();
1082}
1083
1084- (BOOL)isFlipped
1085{
1086 DEBUG_FUNC_ENTER();
1087 DEBUG_FUNC_LEAVE();
1088 return YES;
1089}
1090
1091- (void)drawRect:(NSRect)aRect
1092{
1093 NSRect frame;
1094 DEBUG_FUNC_ENTER();
1095 [self lock];
1096
1097#ifdef SHOW_WINDOW_BACKGROUND
1098 [[NSColor colorWithCalibratedRed:1.0 green:0.0 blue:0.0 alpha:0.7] set];
1099 frame = [self frame];
1100 [NSBezierPath fillRect:NSMakeRect(0, 0, frame.size.width, frame.size.height)];
1101#endif /* SHOW_WINDOW_BACKGROUND */
1102 if (m_ThumbImage != nil)
1103 [m_ThumbImage drawAtPoint:NSMakePoint(0, 0) fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
1104
1105 [self unlock];
1106 DEBUG_FUNC_LEAVE();
1107}
1108
1109- (NSBitmapImageRep *)thumbBitmap
1110{
1111 DEBUG_FUNC_ENTER();
1112 DEBUG_FUNC_LEAVE();
1113 return m_ThumbBitmap;
1114}
1115
1116- (NSImage *)thumbImage
1117{
1118 DEBUG_FUNC_ENTER();
1119 DEBUG_FUNC_LEAVE();
1120 return m_ThumbImage;
1121}
1122@end
1123
1124
1125/********************************************************************************
1126*
1127* OverlayOpenGLContext class implementation
1128*
1129********************************************************************************/
1130@implementation OverlayOpenGLContext
1131
1132-(id)initWithFormat:(NSOpenGLPixelFormat *)format shareContext:(NSOpenGLContext *)share
1133{
1134 DEBUG_FUNC_ENTER();
1135
1136 m_pPixelFormat = NULL;
1137 m_pView = NULL;
1138
1139 self = [super initWithFormat:format shareContext:share];
1140 Assert(self != nil);
1141 if (self)
1142 m_pPixelFormat = format;
1143
1144 DEBUG_MSG(("OCTX(%p): init OverlayOpenGLContext\n", (void *)self));
1145 DEBUG_FUNC_LEAVE();
1146 return self;
1147}
1148
1149- (void)dealloc
1150{
1151 DEBUG_FUNC_ENTER();
1152 DEBUG_MSG(("OCTX(%p): dealloc OverlayOpenGLContext\n", (void *)self));
1153
1154 [m_pPixelFormat release];
1155
1156 [super dealloc];
1157
1158 DEBUG_FUNC_LEAVE();
1159}
1160
1161-(bool)isDoubleBuffer
1162{
1163 DEBUG_FUNC_ENTER();
1164
1165 GLint val;
1166 [m_pPixelFormat getValues:&val forAttribute:NSOpenGLPFADoubleBuffer forVirtualScreen:0];
1167
1168 DEBUG_FUNC_LEAVE();
1169 return val == GL_TRUE ? YES : NO;
1170}
1171
1172-(void)setView:(NSView *)view
1173{
1174 DEBUG_FUNC_ENTER();
1175 DEBUG_MSG(("OCTX(%p): setView: new view: %p\n", (void *)self, (void *)view));
1176
1177#if 1 /* def FBO */
1178 m_pView = view;;
1179#else
1180 [super setView: view];
1181#endif
1182
1183 DEBUG_FUNC_LEAVE();
1184}
1185
1186-(NSView *)view
1187{
1188 DEBUG_FUNC_ENTER();
1189 DEBUG_FUNC_LEAVE();
1190#if 1 /* def FBO */
1191 return m_pView;
1192#else
1193 return [super view];
1194#endif
1195}
1196
1197-(void)clearDrawable
1198{
1199 DEBUG_FUNC_ENTER();
1200 DEBUG_MSG(("OCTX(%p): clearDrawable\n", (void *)self));
1201
1202 m_pView = NULL;;
1203 [super clearDrawable];
1204
1205 DEBUG_FUNC_LEAVE();
1206}
1207
1208-(NSOpenGLPixelFormat *)openGLPixelFormat
1209{
1210 DEBUG_FUNC_ENTER();
1211 DEBUG_FUNC_LEAVE();
1212
1213 return m_pPixelFormat;
1214}
1215
1216@end /* @implementation OverlayOpenGLContext */
1217
1218
1219/********************************************************************************
1220*
1221* OverlayHelperView class implementation
1222*
1223********************************************************************************/
1224@implementation OverlayHelperView
1225
1226-(id)initWithOverlayWindow:(OverlayWindow *)pOverlayWindow
1227{
1228 DEBUG_FUNC_ENTER();
1229
1230 self = [super initWithFrame:NSZeroRect];
1231
1232 m_pOverlayWindow = pOverlayWindow;
1233
1234 DEBUG_MSG(("OHVW(%p): init OverlayHelperView\n", (void *)self));
1235 DEBUG_FUNC_LEAVE();
1236 return self;
1237}
1238
1239-(void)viewDidMoveToWindow
1240{
1241 DEBUG_FUNC_ENTER();
1242 DEBUG_MSG(("OHVW(%p): viewDidMoveToWindow: new win: %p\n", (void *)self, (void *)[self window]));
1243
1244 [m_pOverlayWindow parentWindowChanged:[self window]];
1245
1246 DEBUG_FUNC_LEAVE();
1247}
1248
1249@end
1250
1251
1252/********************************************************************************
1253*
1254* OverlayWindow class implementation
1255*
1256********************************************************************************/
1257@implementation OverlayWindow
1258
1259- (id)initWithParentView:(NSView *)pParentView overlayView:(OverlayView *)pOverlayView
1260{
1261 DEBUG_FUNC_ENTER();
1262 NSWindow *pParentWin = nil;
1263
1264 self = [super initWithContentRect:NSZeroRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO];
1265 if (self)
1266 {
1267 m_pParentView = pParentView;
1268 m_pOverlayView = pOverlayView;
1269 m_Thread = [NSThread currentThread];
1270
1271 [m_pOverlayView setOverlayWin: self];
1272
1273 m_pOverlayHelperView = [[OverlayHelperView alloc] initWithOverlayWindow:self];
1274
1275 /* Add the helper view as a child of the parent view to get notifications */
1276 [pParentView addSubview:m_pOverlayHelperView];
1277
1278 /* Make sure this window is transparent */
1279#ifdef SHOW_WINDOW_BACKGROUND
1280 /* For debugging */
1281 [self setBackgroundColor:[NSColor colorWithCalibratedRed:1.0 green:0.0 blue:0.0 alpha:0.7]];
1282#else
1283 [self setBackgroundColor:[NSColor clearColor]];
1284#endif
1285 [self setOpaque:NO];
1286 [self setAlphaValue:.999];
1287
1288 /* Disable mouse events for this window */
1289 [self setIgnoresMouseEvents:YES];
1290
1291 pParentWin = [m_pParentView window];
1292
1293 /* Initial set the position to the parents view top/left (Compiz fix). */
1294 [self setFrameOrigin:
1295 [pParentWin convertBaseToScreen:
1296 [m_pParentView convertPoint:NSZeroPoint toView:nil]]];
1297
1298 /* Set the overlay view as our content view */
1299 [self setContentView:m_pOverlayView];
1300
1301 /* Add ourself as a child to the parent views window. Note: this has to
1302 * be done last so that everything else is setup in
1303 * parentWindowChanged. */
1304 [pParentWin addChildWindow:self ordered:NSWindowAbove];
1305 }
1306
1307 DEBUG_MSG(("OWIN(%p): init OverlayWindow\n", (void *)self));
1308 DEBUG_FUNC_LEAVE();
1309 return self;
1310}
1311
1312- (void)dealloc
1313{
1314 DEBUG_FUNC_ENTER();
1315 DEBUG_MSG(("OWIN(%p): dealloc OverlayWindow\n", (void *)self));
1316
1317 [[NSNotificationCenter defaultCenter] removeObserver:self];
1318
1319 [m_pOverlayHelperView removeFromSuperview];
1320 [m_pOverlayHelperView release];
1321
1322 [super dealloc];
1323
1324 DEBUG_FUNC_LEAVE();
1325}
1326
1327- (void)parentWindowFrameChanged:(NSNotification *)pNote
1328{
1329 DEBUG_FUNC_ENTER();
1330 DEBUG_MSG(("OWIN(%p): parentWindowFrameChanged\n", (void *)self));
1331
1332 /*
1333 * Reposition this window with the help of the OverlayView. Perform the
1334 * call in the OpenGL thread.
1335 */
1336 /*
1337 [m_pOverlayView performSelector:@selector(vboxReshapePerform) onThread:m_Thread withObject:nil waitUntilDone:YES];
1338 */
1339
1340 if ([m_pOverlayView isEverSized])
1341 {
1342 if ([NSThread isMainThread])
1343 [m_pOverlayView vboxReshapePerform];
1344 else
1345 [self performSelectorOnMainThread:@selector(vboxReshapePerform) withObject:nil waitUntilDone:NO];
1346 }
1347
1348 DEBUG_FUNC_LEAVE();
1349}
1350
1351- (void)parentWindowChanged:(NSWindow *)pWindow
1352{
1353 DEBUG_FUNC_ENTER();
1354 DEBUG_MSG(("OWIN(%p): parentWindowChanged\n", (void *)self));
1355
1356 [[NSNotificationCenter defaultCenter] removeObserver:self];
1357
1358 if (pWindow != nil)
1359 {
1360 /* Ask to get notifications when our parent window frame changes. */
1361 [[NSNotificationCenter defaultCenter]
1362 addObserver:self
1363 selector:@selector(parentWindowFrameChanged:)
1364 name:NSWindowDidResizeNotification
1365 object:pWindow];
1366
1367 /* Add us self as child window */
1368 [pWindow addChildWindow:self ordered:NSWindowAbove];
1369
1370 /*
1371 * Reshape the overlay view after a short waiting time to let the main
1372 * window resize itself properly.
1373 */
1374 /*
1375 [m_pOverlayView performSelector:@selector(vboxReshapePerform) withObject:nil afterDelay:0.2];
1376 [NSTimer scheduledTimerWithTimeInterval:0.2 target:m_pOverlayView selector:@selector(vboxReshapePerform) userInfo:nil repeats:NO];
1377 */
1378
1379 if ([m_pOverlayView isEverSized])
1380 {
1381 if ([NSThread isMainThread])
1382 [m_pOverlayView vboxReshapePerform];
1383 else
1384 [self performSelectorOnMainThread:@selector(vboxReshapePerform) withObject:nil waitUntilDone:NO];
1385 }
1386 }
1387
1388 DEBUG_FUNC_LEAVE();
1389}
1390
1391@end /* @implementation OverlayWindow */
1392
1393
1394
1395/********************************************************************************
1396*
1397* OverlayView class implementation
1398*
1399********************************************************************************/
1400@implementation OverlayView
1401
1402- (id)initWithFrame:(NSRect)frame thread:(RTTHREAD)aThread parentView:(NSView *)pParentView winInfo:(WindowInfo *)pWinInfo
1403{
1404 COCOA_LOG_FLOW(("%s: self=%p aThread=%p pParentView=%p pWinInfo=%p\n", __PRETTY_FUNCTION__, (void *)self,
1405 (void *)aThread, (void *)pParentView, (void *)pWinInfo));
1406
1407 m_pParentView = pParentView;
1408 /* Make some reasonable defaults */
1409 m_pGLCtx = nil;
1410 m_pSharedGLCtx = nil;
1411 m_Thread = aThread;
1412 m_FBOId = 0;
1413 m_cClipRects = 0;
1414 m_paClipRects = NULL;
1415 m_Pos = NSZeroPoint;
1416 m_Size = NSMakeSize(1, 1);
1417 m_RootRect = NSMakeRect(0, 0, m_Size.width, m_Size.height);
1418 m_yInvRootOffset = 0;
1419 m_pBlitter = nil;
1420 m_pWinInfo = pWinInfo;
1421 m_fNeedViewportUpdate = true;
1422 m_fNeedCtxUpdate = true;
1423 m_fDataVisible = false;
1424 m_fCleanupNeeded = false;
1425 m_fEverSized = false;
1426
1427 self = [super initWithFrame:frame];
1428#if defined(VBOX_WITH_CONFIGURABLE_HIDPI_SCALING) && !defined(IN_VMSVGA3D)
1429 /* Always allocate HiDPI-ready backing store for NSView, so we will be able change HiDPI scaling option in runtime. */
1430 crDebug("HiDPI: Allocate big backing store for NSView. Up-scaling is currently %s.", render_spu.fUnscaledHiDPI ? "OFF" : "ON");
1431 [self performSelector:@selector(setWantsBestResolutionOpenGLSurface:) withObject: (id)YES];
1432#endif
1433
1434 COCOA_LOG_FLOW(("%s: returns self=%p\n", __PRETTY_FUNCTION__, (void *)self));
1435 return self;
1436}
1437
1438- (void)cleanupData
1439{
1440 COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
1441
1442 [self deleteDockTile];
1443
1444 [self setGLCtx:nil];
1445
1446 if (m_pSharedGLCtx)
1447 {
1448 if ([m_pSharedGLCtx view] == self)
1449 [m_pSharedGLCtx clearDrawable];
1450
1451 [m_pSharedGLCtx release];
1452 m_pSharedGLCtx = nil;
1453
1454 CrBltTerm(m_pBlitter);
1455 RTMemFree(m_pBlitter);
1456 m_pBlitter = nil;
1457 }
1458
1459 [self clearVisibleRegions];
1460
1461 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
1462}
1463
1464- (void)dealloc
1465{
1466 COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
1467
1468 [self cleanupData];
1469 [super dealloc];
1470
1471 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
1472}
1473
1474- (void)drawRect:(NSRect)aRect
1475{
1476 COCOA_LOG_FLOW(("%s: self=%p aRect=%d,%d %d,%d\n", __PRETTY_FUNCTION__, (void *)self, (int)aRect.origin.x, (int)aRect.origin.y,
1477 (int)aRect.size.width, (int)aRect.size.height));
1478
1479 [self vboxTryDrawUI];
1480
1481 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
1482}
1483
1484- (void)setGLCtx:(NSOpenGLContext *)pCtx
1485{
1486 COCOA_LOG_FLOW(("%s: self=%p pCtx=%p (old=%p)\n", __PRETTY_FUNCTION__, (void *)self, (void *)pCtx, m_pGLCtx));
1487
1488 /*
1489 * Only do something if the context changes.
1490 */
1491 if (m_pGLCtx != pCtx)
1492 {
1493 /* Ensure the context drawable is cleared to avoid holding a reference to inexistent view. */
1494 if (m_pGLCtx)
1495 {
1496#ifdef IN_VMSVGA3D
1497 Assert(!pCtx);
1498#endif
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 - m_pGLCtx=%p m_fNeedCtxUpdate=%d\n", __PRETTY_FUNCTION__, (void *)self,
2003 (void *)m_pGLCtx, m_fNeedCtxUpdate));
2004
2005 if (m_pGLCtx)
2006 {
2007 NSOpenGLContext *pPrevCtx = [NSOpenGLContext currentContext];
2008
2009#ifdef IN_VMSVGA3D
2010 /* Always flush before flush. glXMakeCurrent and wglMakeCurrent does this
2011 implicitly, seemingly NSOpenGLContext::makeCurrentContext doesn't. */
2012 if (pPrevCtx != nil)
2013 {
2014 DEBUG_CLEAR_GL_ERRORS();
2015 glFlush();
2016 DEBUG_CHECK_GL_ERROR("glFlush");
2017 }
2018#endif
2019
2020 if ([m_pGLCtx view] != self)
2021 {
2022#ifndef IN_VMSVGA3D
2023 /* We change the active view, so flush first */
2024 if (pPrevCtx != nil)
2025 glFlush();
2026#endif
2027 DEBUG_CLEAR_GL_ERRORS();
2028 [m_pGLCtx setView: self];
2029 DEBUG_CHECK_GL_ERROR("setView");
2030 }
2031
2032#if 0
2033 if (pPrevCtx != m_pGLCtx)
2034#endif
2035 {
2036 DEBUG_CLEAR_GL_ERRORS();
2037 [m_pGLCtx makeCurrentContext];
2038 DEBUG_CHECK_GL_ERROR("makeCurrentContext");
2039 Assert([NSOpenGLContext currentContext] == m_pGLCtx);
2040 Assert([m_pGLCtx view] == self);
2041 }
2042
2043 if (m_fNeedCtxUpdate == true)
2044 {
2045 [m_pGLCtx update];
2046 m_fNeedCtxUpdate = false;
2047 }
2048
2049 if (!m_FBOId)
2050 {
2051 glGenFramebuffersEXT(1, &m_FBOId);
2052 Assert(m_FBOId);
2053 }
2054 }
2055
2056 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
2057}
2058
2059- (bool)vboxSharedCtxCreate
2060{
2061 COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
2062
2063 if (m_pSharedGLCtx)
2064 {
2065 COCOA_LOG_FLOW(("%s: returns true (m_pSharedGLCtx=%p)\n", __PRETTY_FUNCTION__, (void *)m_pSharedGLCtx));
2066 return true;
2067 }
2068
2069 Assert(!m_pBlitter);
2070 m_pBlitter = RTMemAlloc(sizeof(*m_pBlitter));
2071 if (RT_UNLIKELY(!m_pBlitter))
2072 {
2073 DEBUG_WARN(("m_pBlitter allocation failed"));
2074 COCOA_LOG_FLOW(("%s: returns false - m_pBlitter allocation failed\n", __PRETTY_FUNCTION__));
2075 return false;
2076 }
2077
2078 int rc = CrBltInit(m_pBlitter, NULL, false /*fCreateNewCtx*/, false /*fForceDrawBlt*/,
2079#ifdef IN_VMSVGA3D
2080 NULL /** @todo */, NULL /** @todo */
2081#else
2082 &render_spu.GlobalShaders, &render_spu.blitterDispatch
2083#endif
2084 );
2085 if (RT_FAILURE(rc))
2086 {
2087 DEBUG_WARN(("CrBltInit failed, rc %d", rc));
2088 RTMemFree(m_pBlitter);
2089 m_pBlitter = NULL;
2090
2091 COCOA_LOG_FLOW(("%s: returns false - CrBltInit failed with rc=%Rrc\n", __PRETTY_FUNCTION__, rc));
2092 return false;
2093 }
2094
2095 COCOA_LOG_FLOW(("%s: blitter (%p) created successfully for view 0x%p\n", (void *)m_pBlitter, (void *)self));
2096
2097 /* Create a shared context out of the main context. Use the same pixel format. */
2098 NSOpenGLPixelFormat *pPixelFormat = [(OverlayOpenGLContext *)m_pGLCtx openGLPixelFormat];
2099 NSOpenGLContext *pSharedGLCtx = [[NSOpenGLContext alloc] initWithFormat:pPixelFormat shareContext:m_pGLCtx];
2100
2101 /* Set the new context as non opaque */
2102 GLint opaque = 0;
2103 [pSharedGLCtx setValues:&opaque forParameter:NSOpenGLCPSurfaceOpacity];
2104
2105 /* Set this view as the drawable for the new context */
2106 [pSharedGLCtx setView:self];
2107 m_fNeedViewportUpdate = true;
2108
2109 m_pSharedGLCtx = pSharedGLCtx;
2110
2111 COCOA_LOG_FLOW(("%s: returns true - new m_pSharedGLCtx=%p\n", __PRETTY_FUNCTION__, (void *)m_pSharedGLCtx));
2112 return true;
2113}
2114
2115- (void)vboxTryDraw
2116{
2117 COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
2118
2119 glFlush();
2120
2121 /* Issue to the gui thread. */
2122 [self performSelectorOnMainThread:@selector(vboxTryDrawUI) withObject:nil waitUntilDone:NO];
2123
2124 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
2125}
2126
2127- (void)vboxSetVisible:(GLboolean)fVisible
2128{
2129 COCOA_LOG_FLOW(("%s: self=%p fVisible=%d\n", __PRETTY_FUNCTION__, (void *)self, fVisible));
2130
2131 VBoxMainThreadTaskRunner *pRunner = [VBoxMainThreadTaskRunner globalInstance];
2132 NSNumber *pVisObj = [NSNumber numberWithBool:fVisible];
2133 [pRunner addObj:self selector:@selector(vboxSetVisibleUIObj:) arg:pVisObj];
2134
2135 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
2136}
2137
2138- (void)vboxSetVisibleUI:(GLboolean)fVisible
2139{
2140 COCOA_LOG_FLOW(("%s: self=%p fVisible=%d\n", __PRETTY_FUNCTION__, (void *)self, fVisible));
2141
2142 [self setHidden: !fVisible];
2143
2144 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
2145}
2146
2147- (void)vboxSetVisibleUIObj:(NSNumber *)pVisibleObj
2148{
2149 COCOA_LOG_FLOW(("%s: self=%p pVisibleObj=%p(%d)\n", __PRETTY_FUNCTION__,
2150 (void *)self, (void *)pVisibleObj, [pVisibleObj boolValue]));
2151
2152 BOOL fVisible = [pVisibleObj boolValue];
2153 [self vboxSetVisibleUI:fVisible];
2154
2155 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
2156}
2157
2158- (void)vboxReparent:(NSView *)pParentView
2159{
2160 COCOA_LOG_FLOW(("%s: self=%p pParentView=%p\n", __PRETTY_FUNCTION__, (void *)self, (void *)pParentView));
2161
2162 VBoxMainThreadTaskRunner *pRunner = [VBoxMainThreadTaskRunner globalInstance];
2163 [pRunner addObj:self selector:@selector(vboxReparentUI:) arg:pParentView];
2164
2165 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
2166}
2167
2168- (void)vboxReparentUI:(NSView *)pParentView
2169{
2170 COCOA_LOG_FLOW(("%s: self=%p pParentView=%p\n", __PRETTY_FUNCTION__, (void *)self, (void *)pParentView));
2171
2172 /* Make sure the window is removed from any previous parent window. */
2173 if ([[self overlayWin] parentWindow] != nil)
2174 {
2175 [[[self overlayWin] parentWindow] removeChildWindow:[self overlayWin]];
2176 }
2177
2178 /* Set the new parent view */
2179 [self setParentView: pParentView];
2180
2181 /* Add the overlay window as a child to the new parent window */
2182 if (pParentView != nil)
2183 {
2184 [[pParentView window] addChildWindow:[self overlayWin] ordered:NSWindowAbove];
2185 if ([self isEverSized])
2186 [self vboxReshapeOnReparentPerform];
2187 }
2188
2189 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
2190}
2191
2192- (void)vboxTryDrawUI
2193{
2194 COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
2195
2196 if ([self isHidden])
2197 {
2198 COCOA_LOG_FLOW(("%s: returns - request to draw on a hidden view\n", __PRETTY_FUNCTION__));
2199 return;
2200 }
2201
2202 if ([[self overlayWin] parentWindow] == nil)
2203 {
2204 COCOA_LOG_FLOW(("%s: returns - request to draw a view w/o a parent\n", __PRETTY_FUNCTION__));
2205 return;
2206 }
2207
2208#ifdef IN_VMSVGA3D
2209 if (!m_pSharedGLCtx)
2210 {
2211 Assert(!m_fDataVisible);
2212 Assert(!m_fCleanupNeeded);
2213 if (![self vboxSharedCtxCreate])
2214 {
2215 COCOA_LOG_FLOW(("%s: returns - vboxSharedCtxCreate failed\n", __PRETTY_FUNCTION__));
2216 return;
2217 }
2218 Assert(m_pSharedGLCtx);
2219 }
2220#endif
2221
2222 const VBOXVR_SCR_COMPOSITOR *pCompositor;
2223 int rc = renderspuVBoxCompositorLock(m_pWinInfo, &pCompositor);
2224 if (RT_FAILURE(rc))
2225 {
2226 COCOA_LOG_FLOW(("%s: returns - renderspuVBoxCompositorLock failed (%Rrc)\n", __PRETTY_FUNCTION__, rc));
2227 return;
2228 }
2229
2230#ifndef IN_VMSVGA3D
2231 if (!pCompositor && !m_fCleanupNeeded)
2232 {
2233 renderspuVBoxCompositorUnlock(m_pWinInfo);
2234 COCOA_LOG_FLOW(("%s: returns - noCompositorUI\n", __PRETTY_FUNCTION__));
2235 return;
2236 }
2237#endif
2238
2239 VBOXVR_SCR_COMPOSITOR TmpCompositor;
2240
2241 if (pCompositor)
2242 {
2243 if (!m_pSharedGLCtx)
2244 {
2245 Assert(!m_fDataVisible);
2246 Assert(!m_fCleanupNeeded);
2247 renderspuVBoxCompositorRelease(m_pWinInfo);
2248 if (![self vboxSharedCtxCreate])
2249 {
2250 COCOA_LOG_FLOW(("%s: returns - vboxSharedCtxCreate failed\n", __PRETTY_FUNCTION__));
2251 return;
2252 }
2253
2254 Assert(m_pSharedGLCtx);
2255
2256 pCompositor = renderspuVBoxCompositorAcquire(m_pWinInfo);
2257 Assert(!m_fDataVisible);
2258 Assert(!m_fCleanupNeeded);
2259 if (!pCompositor)
2260 {
2261 COCOA_LOG_FLOW(("%s: returns - Failed to reacquire compositor\n", __PRETTY_FUNCTION__));
2262 return;
2263 }
2264 }
2265 }
2266 else
2267 {
2268 DEBUG_MSG(("%s: NeedCleanup\n", __PRETTY_FUNCTION__));
2269#ifndef IN_VMSVGA3D /** @todo VMSVGA3 */
2270 Assert(m_fCleanupNeeded);
2271#endif
2272 CrVrScrCompositorInit(&TmpCompositor, NULL);
2273 pCompositor = &TmpCompositor;
2274 }
2275
2276 if ([self lockFocusIfCanDraw])
2277 {
2278 COCOA_LOG_FLOW(("%s: Calling vboxPresent\n", __PRETTY_FUNCTION__));
2279 [self vboxPresent:pCompositor];
2280 [self unlockFocus];
2281 }
2282#ifndef IN_VMSVGA3D /** @todo VMSVGA3 */
2283 else if (!m_pWinInfo->visible)
2284 {
2285 COCOA_LOG_FLOW(("%s: NotVisible\n", __PRETTY_FUNCTION__));
2286 m_fCleanupNeeded = false;
2287 }
2288#endif
2289 else
2290 {
2291 COCOA_LOG_FLOW(("%s: Reschedule\n", __PRETTY_FUNCTION__));
2292 [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(vboxTryDrawUI) userInfo:nil repeats:NO];
2293 }
2294
2295 renderspuVBoxCompositorUnlock(m_pWinInfo);
2296 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
2297}
2298
2299- (void)swapFBO
2300{
2301 COCOA_LOG_FLOW(("%s: self=%p - m_pGLCtx=%p\n", __PRETTY_FUNCTION__, (void *)self, (void *)m_pGLCtx));
2302 [m_pGLCtx flushBuffer];
2303 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
2304}
2305
2306- (void)vboxPresent:(PCVBOXVR_SCR_COMPOSITOR)pCompositor
2307{
2308 COCOA_LOG_FLOW(("%s: self=%p pCompositor=%p\n", __PRETTY_FUNCTION__, (void *)self, (void *)pCompositor));
2309 /*DEBUG_MSG(("OVIW(%p): renderFBOToView\n", (void *)self));*/
2310 AssertPtr(pCompositor);
2311
2312 VBOX_CR_RENDER_CTX_INFO CtxInfo;
2313 vboxCtxEnter(m_pSharedGLCtx, &CtxInfo);
2314
2315 [self vboxPresentCS:pCompositor];
2316
2317 vboxCtxLeave(&CtxInfo);
2318 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
2319}
2320
2321- (void)vboxPresentCS:(PCVBOXVR_SCR_COMPOSITOR)pCompositor
2322{
2323 COCOA_LOG_FLOW(("%s: self=%p pCompositor=%p\n", __PRETTY_FUNCTION__, (void *)self, (void *)pCompositor));
2324 if ([m_pSharedGLCtx view] != self)
2325 {
2326 COCOA_LOG_FLOW(("%s: Not current view of shared ctx! Switching... (self=%p, view=%p, m_pSharedGLCtx)\n",
2327 __PRETTY_FUNCTION__, (void *)self, (void *)[m_pSharedGLCtx view], (void *)m_pSharedGLCtx));
2328 [m_pSharedGLCtx setView: self];
2329 m_fNeedViewportUpdate = true;
2330 }
2331
2332 if (m_fNeedViewportUpdate)
2333 {
2334 [self updateViewportCS];
2335 m_fNeedViewportUpdate = false;
2336 }
2337
2338 m_fCleanupNeeded = false;
2339
2340 /* Render FBO content to the dock tile when necessary. */
2341 [self vboxPresentToDockTileCS:pCompositor];
2342
2343 /* change to #if 0 to see thumbnail image */
2344#if 1
2345 [self vboxPresentToViewCS:pCompositor];
2346#else
2347 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
2348 [m_pSharedGLCtx flushBuffer];
2349#endif
2350
2351 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
2352}
2353
2354DECLINLINE(void) vboxNSRectToRect(const NSRect *pR, RTRECT *pRect)
2355{
2356 pRect->xLeft = (int)pR->origin.x;
2357 pRect->yTop = (int)pR->origin.y;
2358 pRect->xRight = (int)(pR->origin.x + pR->size.width);
2359 pRect->yBottom = (int)(pR->origin.y + pR->size.height);
2360}
2361
2362DECLINLINE(void) vboxNSRectToRectUnstretched(const NSRect *pR, RTRECT *pRect, float xStretch, float yStretch)
2363{
2364 pRect->xLeft = (int)(pR->origin.x / xStretch);
2365 pRect->yTop = (int)(pR->origin.y / yStretch);
2366 pRect->xRight = (int)((pR->origin.x + pR->size.width) / xStretch);
2367 pRect->yBottom = (int)((pR->origin.y + pR->size.height) / yStretch);
2368}
2369
2370DECLINLINE(void) vboxNSRectToRectStretched(const NSRect *pR, RTRECT *pRect, float xStretch, float yStretch)
2371{
2372 pRect->xLeft = (int)(pR->origin.x * xStretch);
2373 pRect->yTop = (int)(pR->origin.y * yStretch);
2374 pRect->xRight = (int)((pR->origin.x + pR->size.width) * xStretch);
2375 pRect->yBottom = (int)((pR->origin.y + pR->size.height) * yStretch);
2376}
2377
2378- (void)vboxPresentToViewCS:(PCVBOXVR_SCR_COMPOSITOR)pCompositor
2379{
2380 NSRect r = [self frame];
2381 COCOA_LOG_FLOW(("%s: self=%p - r={%d,%d %d,%d}\n", __PRETTY_FUNCTION__, (void *)self,
2382 (int)r.origin.x, (int)r.origin.y, (int)r.size.width, (int)r.size.height));
2383
2384#if 1 /* Set to 0 to see the docktile instead of the real output */
2385 VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR CIter;
2386 const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry;
2387
2388 CrVrScrCompositorConstIterInit(pCompositor, &CIter);
2389
2390 float backingStretchFactor = 1.;
2391#if defined(VBOX_WITH_CONFIGURABLE_HIDPI_SCALING) && !defined(IN_VMSVGA3D)
2392 /* Adjust viewport according to current NSView's backing store parameters. */
2393 if (render_spu.fUnscaledHiDPI)
2394 {
2395 /* Update stretch factor in order to satisfy current NSView's backing store parameters. */
2396 backingStretchFactor = [self safeGetBackingScaleFactor];
2397 }
2398
2399 NSRect regularBounds = [self bounds];
2400 NSRect backingBounds = [self safeConvertRectToBacking:&regularBounds];
2401 glViewport(0, 0, backingBounds.size.width, backingBounds.size.height);
2402
2403 crDebug("HiDPI: vboxPresentToViewCS: up-scaling is %s (backingStretchFactor=%d).",
2404 render_spu.fUnscaledHiDPI ? "OFF" : "ON", (int)backingStretchFactor);
2405#endif
2406
2407 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
2408 glDrawBuffer(GL_BACK);
2409
2410 /* Clear background to transparent */
2411 glClear(GL_COLOR_BUFFER_BIT);
2412
2413 m_fDataVisible = false;
2414
2415 float xStretch;
2416 float yStretch;
2417 CrVrScrCompositorGetStretching(pCompositor, &xStretch, &yStretch);
2418
2419 while ((pEntry = CrVrScrCompositorConstIterNext(&CIter)) != NULL)
2420 {
2421 uint32_t cRegions;
2422 const RTRECT *paSrcRegions, *paDstRegions;
2423 int rc = CrVrScrCompositorEntryRegionsGet(pCompositor, pEntry, &cRegions, &paSrcRegions, &paDstRegions, NULL);
2424 uint32_t fFlags = CrVrScrCompositorEntryFlagsCombinedGet(pCompositor, pEntry);
2425 if (RT_SUCCESS(rc))
2426 {
2427 rc = CrBltEnter(m_pBlitter);
2428 if (RT_SUCCESS(rc))
2429 {
2430 uint32_t i;
2431 for (i = 0; i < cRegions; ++i)
2432 {
2433 const CR_TEXDATA *pTexData;
2434 PCRTRECT pSrcRect = &paSrcRegions[i];
2435 PCRTRECT pDstRect = &paDstRegions[i];
2436 RTRECT DstRect, RestrictDstRect;
2437 RTRECT SrcRect, RestrictSrcRect;
2438
2439 vboxNSRectToRect(&m_RootRect, &RestrictDstRect);
2440 VBoxRectIntersected(&RestrictDstRect, pDstRect, &DstRect);
2441
2442 if (VBoxRectIsZero(&DstRect))
2443 continue;
2444
2445 VBoxRectTranslate(&DstRect, -RestrictDstRect.xLeft, -RestrictDstRect.yTop);
2446
2447 vboxNSRectToRectUnstretched(&m_RootRect, &RestrictSrcRect, xStretch / backingStretchFactor, yStretch / backingStretchFactor);
2448 VBoxRectTranslate(&RestrictSrcRect,
2449 -CrVrScrCompositorEntryRectGet(pEntry)->xLeft,
2450 -CrVrScrCompositorEntryRectGet(pEntry)->yTop);
2451 VBoxRectIntersected(&RestrictSrcRect, pSrcRect, &SrcRect);
2452
2453 if (VBoxRectIsZero(&SrcRect))
2454 continue;
2455
2456 pSrcRect = &SrcRect;
2457 pDstRect = &DstRect;
2458
2459 pTexData = CrVrScrCompositorEntryTexGet(pEntry);
2460
2461 CrBltBlitTexMural(m_pBlitter, true, CrTdTexGet(pTexData), pSrcRect, pDstRect, 1, fFlags | CRBLT_F_NOALPHA);
2462
2463 m_fDataVisible = true;
2464 }
2465 CrBltLeave(m_pBlitter);
2466 }
2467 else
2468 {
2469 DEBUG_WARN(("CrBltEnter failed rc %d", rc));
2470# ifndef DEBUG_VERBOSE
2471 AssertMsgFailed(("CrBltEnter failed rc %Rrc", rc));
2472# endif
2473 }
2474 }
2475 else
2476 {
2477 AssertMsgFailed(("BlitStretched: CrVrScrCompositorEntryRegionsGet failed rc %Rrc\n", rc));
2478 DEBUG_MSG_1(("BlitStretched: CrVrScrCompositorEntryRegionsGet failed rc %d\n", rc));
2479 }
2480 }
2481#endif
2482
2483 /*
2484 glFinish();
2485 */
2486 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
2487 [m_pSharedGLCtx flushBuffer];
2488
2489 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
2490}
2491
2492- (void)presentComposition:(PCVBOXVR_SCR_COMPOSITOR_ENTRY)pChangedEntry
2493{
2494 COCOA_LOG_FLOW(("%s: self=%p pChangedEntry=%p\n", __PRETTY_FUNCTION__, (void *)self, (void *)pChangedEntry));
2495 [self vboxTryDraw];
2496}
2497
2498- (void)vboxBlitterSyncWindow
2499{
2500 COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
2501 CR_BLITTER_WINDOW WinInfo;
2502 NSRect r;
2503
2504 if (!m_pBlitter)
2505 return;
2506
2507 RT_ZERO(WinInfo);
2508
2509 r = [self frame];
2510 WinInfo.width = r.size.width;
2511 WinInfo.height = r.size.height;
2512
2513 Assert(WinInfo.width == m_RootRect.size.width);
2514 Assert(WinInfo.height == m_RootRect.size.height);
2515
2516 /*CrBltMuralSetCurrentInfo(m_pBlitter, NULL);*/
2517
2518 CrBltMuralSetCurrentInfo(m_pBlitter, &WinInfo);
2519 CrBltCheckUpdateViewport(m_pBlitter);
2520}
2521
2522#ifdef VBOX_WITH_CRDUMPER_THUMBNAIL
2523static int g_cVBoxTgaCtr = 0;
2524#endif
2525- (void)vboxPresentToDockTileCS:(PCVBOXVR_SCR_COMPOSITOR)pCompositor
2526{
2527 COCOA_LOG_FLOW(("%s: self=%p pCompositor=%p\n", __PRETTY_FUNCTION__, (void *)self, (void *)pCompositor));
2528 NSRect r = [self frame];
2529 NSRect rr = NSZeroRect;
2530 NSDockTile *pDT = nil;
2531 float xStretch;
2532 float yStretch;
2533
2534 if ([m_DockTileView thumbBitmap] != nil)
2535 {
2536 /*
2537 * Only update after at least 200 ms, cause glReadPixels is
2538 * heavy performance wise.
2539 */
2540 uint64_t msTS = RTTimeSystemMilliTS();
2541 VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR CIter;
2542 const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry;
2543
2544 if (msTS - m_msDockUpdateTS > 200)
2545 {
2546 m_msDockUpdateTS = msTS;
2547#if 0
2548 /* todo: check this for optimization */
2549 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, myTextureName);
2550 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_STORAGE_HINT_APPLE,
2551 GL_STORAGE_SHARED_APPLE);
2552 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2553 glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA,
2554 sizex, sizey, 0, GL_BGRA,
2555 GL_UNSIGNED_INT_8_8_8_8_REV, myImagePtr);
2556 glCopyTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB,
2557 0, 0, 0, 0, 0, image_width, image_height);
2558 glFlush();
2559 /* Do other work processing here, using a double or triple buffer */
2560 glGetTexImage(GL_TEXTURE_RECTANGLE_ARB, 0, GL_BGRA,
2561 GL_UNSIGNED_INT_8_8_8_8_REV, pixels);
2562#endif
2563 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
2564 glDrawBuffer(GL_BACK);
2565
2566 /* Clear background to transparent */
2567 glClear(GL_COLOR_BUFFER_BIT);
2568
2569 rr = [m_DockTileView frame];
2570
2571 CrVrScrCompositorGetStretching(pCompositor, &xStretch, &yStretch);
2572
2573 CrVrScrCompositorConstIterInit(pCompositor, &CIter);
2574 while ((pEntry = CrVrScrCompositorConstIterNext(&CIter)) != NULL)
2575 {
2576 uint32_t cRegions;
2577 PCRTRECT paSrcRegions;
2578 PCRTRECT paDstRegions;
2579 int rc = CrVrScrCompositorEntryRegionsGet(pCompositor, pEntry, &cRegions, &paSrcRegions, &paDstRegions, NULL);
2580 uint32_t fFlags = CrVrScrCompositorEntryFlagsCombinedGet(pCompositor, pEntry);
2581 if (RT_SUCCESS(rc))
2582 {
2583 rc = CrBltEnter(m_pBlitter);
2584 if (RT_SUCCESS(rc))
2585 {
2586 uint32_t i;
2587 for (i = 0; i < cRegions; ++i)
2588 {
2589 const CR_TEXDATA *pTexData;
2590 PCRTRECT pSrcRect = &paSrcRegions[i];
2591 PCRTRECT pDstRect = &paDstRegions[i];
2592 RTRECT DstRect, RestrictDstRect;
2593 RTRECT SrcRect, RestrictSrcRect;
2594
2595 vboxNSRectToRect(&m_RootRect, &RestrictDstRect);
2596 VBoxRectIntersected(&RestrictDstRect, pDstRect, &DstRect);
2597
2598 VBoxRectTranslate(&DstRect, -RestrictDstRect.xLeft, -RestrictDstRect.yTop);
2599
2600 VBoxRectScale(&DstRect, m_FBOThumbScaleX, m_FBOThumbScaleY);
2601
2602 if (VBoxRectIsZero(&DstRect))
2603 continue;
2604
2605 vboxNSRectToRectUnstretched(&m_RootRect, &RestrictSrcRect, xStretch, yStretch);
2606 VBoxRectTranslate(&RestrictSrcRect,
2607 -CrVrScrCompositorEntryRectGet(pEntry)->xLeft,
2608 -CrVrScrCompositorEntryRectGet(pEntry)->yTop);
2609 VBoxRectIntersected(&RestrictSrcRect, pSrcRect, &SrcRect);
2610
2611 if (VBoxRectIsZero(&SrcRect))
2612 continue;
2613
2614 pSrcRect = &SrcRect;
2615 pDstRect = &DstRect;
2616
2617 pTexData = CrVrScrCompositorEntryTexGet(pEntry);
2618
2619 CrBltBlitTexMural(m_pBlitter, true, CrTdTexGet(pTexData), pSrcRect, pDstRect, 1, fFlags);
2620 }
2621 CrBltLeave(m_pBlitter);
2622 }
2623 else
2624 {
2625 DEBUG_WARN(("CrBltEnter failed rc %d", rc));
2626#ifndef DEBUG_VERBOSE
2627 AssertMsgFailed(("CrBltEnter failed rc %Rrc", rc));
2628#endif
2629 }
2630 }
2631 else
2632 {
2633 DEBUG_MSG_1(("BlitStretched: CrVrScrCompositorEntryRegionsGet failed rc %d\n", rc));
2634 AssertMsgFailed(("BlitStretched: CrVrScrCompositorEntryRegionsGet failed rc %Rrc\n", rc));
2635 }
2636 }
2637
2638 glFinish();
2639
2640 glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
2641 glReadBuffer(GL_BACK);
2642
2643 /* Here the magic of reading the FBO content in our own buffer
2644 * happens. We have to lock this access, in the case the dock
2645 * is updated currently. */
2646 [m_DockTileView lock];
2647 glReadPixels(0, m_RootRect.size.height - rr.size.height, rr.size.width, rr.size.height,
2648 GL_BGRA,
2649 GL_UNSIGNED_INT_8_8_8_8,
2650 [[m_DockTileView thumbBitmap] bitmapData]);
2651 [m_DockTileView unlock];
2652
2653#ifdef VBOX_WITH_CRDUMPER_THUMBNAIL
2654 ++g_cVBoxTgaCtr;
2655 crDumpNamedTGAF((GLint)rr.size.width, (GLint)rr.size.height,
2656 [[m_DockTileView thumbBitmap] bitmapData], "/Users/leo/vboxdumps/dump%d.tga", g_cVBoxTgaCtr);
2657#endif
2658
2659 pDT = [[NSApplication sharedApplication] dockTile];
2660
2661 /* Send a display message to the dock tile in the main thread */
2662 [[[NSApplication sharedApplication] dockTile] performSelectorOnMainThread:@selector(display) withObject:nil
2663 waitUntilDone:NO];
2664 }
2665 }
2666}
2667
2668- (void)clearVisibleRegions
2669{
2670 if (m_paClipRects)
2671 {
2672 RTMemFree(m_paClipRects);
2673 m_paClipRects = NULL;
2674 }
2675 m_cClipRects = 0;
2676}
2677
2678- (GLboolean)vboxNeedsEmptyPresent
2679{
2680 if (m_fDataVisible)
2681 {
2682 m_fCleanupNeeded = true;
2683 return GL_TRUE;
2684 }
2685
2686 return GL_FALSE;
2687}
2688
2689- (void)setVisibleRegions:(GLint)cRects paRects:(const GLint *)paRects
2690{
2691 COCOA_LOG_FLOW(("%s: self=%p cRects=%d paRects=%p\n", __PRETTY_FUNCTION__, (void *)self, cRects, (void *)paRects));
2692 GLint cOldRects = m_cClipRects;
2693
2694 [self clearVisibleRegions];
2695
2696 if (cRects > 0)
2697 {
2698#ifdef DEBUG_poetzsch
2699 int i = 0;
2700 for (i = 0; i < cRects; ++i)
2701 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]));
2702#endif
2703
2704 m_paClipRects = (GLint *)RTMemDup(paRects, sizeof(GLint) * 4 * cRects);
2705 m_cClipRects = cRects;
2706 }
2707
2708 COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
2709}
2710
2711- (NSView *)dockTileScreen
2712{
2713 COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
2714 NSView *pContentView = [[[NSApplication sharedApplication] dockTile] contentView];
2715 NSView *pScreenContent = nil;
2716
2717 /*
2718 * First try the new variant which checks if this window is within the
2719 * screen which is previewed in the dock.
2720 */
2721 if ([pContentView respondsToSelector:@selector(screenContentWithParentView:)])
2722 pScreenContent = [pContentView performSelector:@selector(screenContentWithParentView:) withObject:(id)m_pParentView];
2723 /*
2724 * If it fails, fall back to the old variant (VBox...).
2725 */
2726 else if ([pContentView respondsToSelector:@selector(screenContent)])
2727 pScreenContent = [pContentView performSelector:@selector(screenContent)];
2728
2729 COCOA_LOG_FLOW(("%s: returns %p (pContentView=%p)\n", __PRETTY_FUNCTION__, (void *)pScreenContent, (void *)pContentView));
2730 return pScreenContent;
2731}
2732
2733- (void)reshapeDockTile
2734{
2735 COCOA_LOG_FLOW(("%s:\n", __PRETTY_FUNCTION__));
2736 NSRect newFrame = NSZeroRect;
2737 NSView *pView = [self dockTileScreen];
2738 if (pView != nil)
2739 {
2740 NSRect dockFrame = [pView frame];
2741 /** @todo This is not correct, we should use framebuffer size here, while
2742 * parent view frame size may differ in case of scrolling. */
2743 NSRect parentFrame = [m_pParentView frame];
2744
2745 m_FBOThumbScaleX = (float)dockFrame.size.width / parentFrame.size.width;
2746 m_FBOThumbScaleY = (float)dockFrame.size.height / parentFrame.size.height;
2747 newFrame = NSMakeRect((int)(m_Pos.x * m_FBOThumbScaleX),
2748 (int)(dockFrame.size.height - (m_Pos.y + m_Size.height - m_yInvRootOffset) * m_FBOThumbScaleY),
2749 (int)(m_Size.width * m_FBOThumbScaleX),
2750 (int)(m_Size.height * m_FBOThumbScaleY));
2751 /*
2752 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));
2753 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));
2754 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);
2755 */
2756 [m_DockTileView setFrame: newFrame];
2757 }
2758 COCOA_LOG_FLOW(("%s: returns - newFrame={%d,%d %d,%d} pView=%d\n", __PRETTY_FUNCTION__, (int)newFrame.origin.x,
2759 (int)newFrame.origin.y, (int)newFrame.size.width, (int)newFrame.size.height, (void *)pView));
2760}
2761
2762@end /* @implementation OverlayView */
2763
2764
2765/********************************************************************************
2766*
2767* OpenGL context management
2768*
2769********************************************************************************/
2770void cocoaGLCtxCreate(NativeNSOpenGLContextRef *ppCtx, GLbitfield fVisParams, NativeNSOpenGLContextRef pSharedCtx)
2771{
2772 COCOA_LOG_FLOW(("cocoaGLCtxCreate: ppCtx=%p fVisParams=%#x pSharedCtx=%p\n", (void *)ppCtx, fVisParams, (void *)pSharedCtx));
2773 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
2774 NSOpenGLPixelFormat *pFmt = nil;
2775
2776 NSOpenGLPixelFormatAttribute attribs[24] =
2777 {
2778#ifdef IN_VMSVGA3D
2779 NSOpenGLPFAOpenGLProfile, (NSOpenGLPixelFormatAttribute)0,
2780#endif
2781 NSOpenGLPFAAccelerated,
2782 NSOpenGLPFAColorSize, (NSOpenGLPixelFormatAttribute)24
2783 };
2784
2785 int i = 3;
2786
2787#ifdef IN_VMSVGA3D
2788 if (fVisParams & VMSVGA3D_NON_DEFAULT_PROFILE_BIT)
2789 attribs[1] = VBOX_VMSVGA3D_DEFAULT_OGL_PROFILE >= 3.2 ? NSOpenGLProfileVersionLegacy : NSOpenGLProfileVersion3_2Core;
2790 else
2791 attribs[1] = VBOX_VMSVGA3D_DEFAULT_OGL_PROFILE >= 3.2 ? NSOpenGLProfileVersion3_2Core : NSOpenGLProfileVersionLegacy;
2792#endif
2793
2794 if (fVisParams & CR_ALPHA_BIT)
2795 {
2796 COCOA_LOG_FLOW((" CR_ALPHA_BIT requested\n"));
2797 attribs[i++] = NSOpenGLPFAAlphaSize;
2798 attribs[i++] = 8;
2799 }
2800 if (fVisParams & CR_DEPTH_BIT)
2801 {
2802 COCOA_LOG_FLOW((" CR_DEPTH_BIT requested\n"));
2803 attribs[i++] = NSOpenGLPFADepthSize;
2804 attribs[i++] = 24;
2805 }
2806 if (fVisParams & CR_STENCIL_BIT)
2807 {
2808 COCOA_LOG_FLOW((" CR_STENCIL_BIT requested\n"));
2809 attribs[i++] = NSOpenGLPFAStencilSize;
2810 attribs[i++] = 8;
2811 }
2812 if (fVisParams & CR_ACCUM_BIT)
2813 {
2814 COCOA_LOG_FLOW((" CR_ACCUM_BIT requested\n"));
2815 attribs[i++] = NSOpenGLPFAAccumSize;
2816 if (fVisParams & CR_ALPHA_BIT)
2817 attribs[i++] = 32;
2818 else
2819 attribs[i++] = 24;
2820 }
2821 if (fVisParams & CR_MULTISAMPLE_BIT)
2822 {
2823 COCOA_LOG_FLOW((" CR_MULTISAMPLE_BIT requested\n"));
2824 attribs[i++] = NSOpenGLPFASampleBuffers;
2825 attribs[i++] = 1;
2826 attribs[i++] = NSOpenGLPFASamples;
2827 attribs[i++] = 4;
2828 }
2829 if (fVisParams & CR_DOUBLE_BIT)
2830 {
2831 COCOA_LOG_FLOW((" CR_DOUBLE_BIT requested\n"));
2832 attribs[i++] = NSOpenGLPFADoubleBuffer;
2833 }
2834 if (fVisParams & CR_STEREO_BIT)
2835 {
2836 /* We don't support that.
2837 COCOA_LOG_FLOW((" CR_STEREO_BIT requested\n"));
2838 attribs[i++] = NSOpenGLPFAStereo;
2839 */
2840 }
2841
2842 if (VBoxOglIsOfflineRenderingAppropriate())
2843 {
2844 COCOA_LOG_FLOW((" Offline rendering is enabled\n"));
2845 attribs[i++] = NSOpenGLPFAAllowOfflineRenderers;
2846 }
2847
2848 /* Mark the end */
2849 attribs[i++] = 0;
2850
2851 /* Choose a pixel format */
2852 pFmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
2853
2854 if (pFmt)
2855 {
2856 *ppCtx = [[OverlayOpenGLContext alloc] initWithFormat:pFmt shareContext:pSharedCtx];
2857 Assert(*ppCtx);
2858
2859 /* Enable multi threaded OpenGL engine */
2860 /*
2861 CGLContextObj cglCtx = [*ppCtx CGLContextObj];
2862 CGLError err = CGLEnable(cglCtx, kCGLCEMPEngine);
2863 if (err != kCGLNoError)
2864 printf ("Couldn't enable MT OpenGL engine!\n");
2865 */
2866 }
2867 else
2868 {
2869 AssertFailed();
2870 *ppCtx = NULL;
2871 }
2872
2873 [pPool release];
2874 COCOA_LOG_FLOW(("cocoaGLCtxCreate: returns *ppCtx=%p\n", (void *)*ppCtx));
2875}
2876
2877void cocoaGLCtxDestroy(NativeNSOpenGLContextRef pCtx)
2878{
2879 COCOA_LOG_FLOW(("cocoaGLCtxDestroy: pCtx=%p\n", (void *)pCtx));
2880 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
2881
2882 [pCtx release];
2883 /*[pCtx performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO];*/
2884
2885 [pPool release];
2886 COCOA_LOG_FLOW(("cocoaGLCtxDestroy: returns\n"));
2887}
2888
2889/********************************************************************************
2890*
2891* View management
2892*
2893********************************************************************************/
2894static OverlayView *vboxViewCreate(WindowInfo *pWinInfo, NativeNSViewRef pParentView)
2895{
2896 COCOA_LOG_FLOW(("vboxViewCreate: pWinInfo=%p pParentView=%p\n", pWinInfo, (void *)pParentView));
2897
2898 /* Create our worker view. */
2899 OverlayView *pView = [[OverlayView alloc] initWithFrame:NSZeroRect
2900 thread:RTThreadSelf()
2901 parentView:pParentView
2902 winInfo:pWinInfo];
2903
2904 if (pView)
2905 {
2906 /* We need a real window as container for the view */
2907 [[OverlayWindow alloc] initWithParentView:pParentView overlayView:pView];
2908 /* Return the freshly created overlay view */
2909 COCOA_LOG_FLOW(("vboxViewCreate: returns %p\n", (void *)pView));
2910 return pView;
2911 }
2912
2913 COCOA_LOG_FLOW(("vboxViewCreate: returns NULL\n"));
2914 return NULL;
2915}
2916
2917#ifndef IN_VMSVGA3D
2918
2919typedef struct CR_RCD_CREATEVIEW
2920{
2921 WindowInfo *pWinInfo;
2922 NSView *pParentView;
2923 GLbitfield fVisParams;
2924 /* out */
2925 OverlayView *pView;
2926} CR_RCD_CREATEVIEW;
2927
2928static DECLCALLBACK(void) vboxRcdCreateView(void *pvCb)
2929{
2930 CR_RCD_CREATEVIEW *pCreateView = (CR_RCD_CREATEVIEW *)pvCb;
2931 pCreateView->pView = vboxViewCreate(pCreateView->pWinInfo, pCreateView->pParentView);
2932 COCOA_LOG_FLOW(("vboxRcdCreateView: returns pView=%p\n", (void *)pCreateView->pView));
2933}
2934
2935#endif /* !IN_VMSVGA3D */
2936
2937void cocoaViewCreate(NativeNSViewRef *ppView, WindowInfo *pWinInfo, NativeNSViewRef pParentView, GLbitfield fVisParams)
2938{
2939 COCOA_LOG_FLOW(("cocoaViewCreate: ppView=%p pWinInfo=%p pParentView=%p fVisParams=%#x\n",
2940 (void *)ppView, (void *)pWinInfo, (void *)pParentView, fVisParams));
2941 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
2942
2943 /* make sure all tasks are run, to preserve the order */
2944 VBoxMainThreadTaskRunner *pRunner = [VBoxMainThreadTaskRunner globalInstance];
2945 [pRunner runTasksSyncIfPossible];
2946
2947 renderspuWinRetain(pWinInfo);
2948
2949#ifndef IN_VMSVGA3D
2950 if (renderspuCalloutAvailable())
2951 {
2952 CR_RCD_CREATEVIEW CreateView;
2953 CreateView.pWinInfo = pWinInfo;
2954 CreateView.pParentView = pParentView;
2955 CreateView.fVisParams = fVisParams;
2956 CreateView.pView = NULL;
2957 renderspuCalloutClient(vboxRcdCreateView, &CreateView);
2958 *ppView = CreateView.pView;
2959 }
2960 else
2961#endif
2962 {
2963 DEBUG_MSG_NOT_VMSVGA3D(("no callout available on createWindow\n"));
2964#if 0
2965 dispatch_sync(dispatch_get_main_queue(), ^{
2966#endif
2967 *ppView = vboxViewCreate(pWinInfo, pParentView);
2968#if 0
2969 });
2970#endif
2971 }
2972
2973 if (!*ppView)
2974 renderspuWinRelease(pWinInfo);
2975
2976 [pPool release];
2977 COCOA_LOG_FLOW(("cocoaViewCreate: returns *ppView=%p\n", (void *)*ppView));
2978}
2979
2980void cocoaViewReparent(NativeNSViewRef pView, NativeNSViewRef pParentView)
2981{
2982 COCOA_LOG_FLOW(("cocoaViewReparent: pView=%p pParentView=%p\n", (void *)pView, (void *)pParentView));
2983 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
2984
2985 OverlayView *pOView = (OverlayView *)pView;
2986 if (pOView)
2987 [pOView vboxReparent:pParentView];
2988
2989 [pPool release];
2990 COCOA_LOG_FLOW(("cocoaViewReparent: returns\n"));
2991}
2992
2993void cocoaViewDestroy(NativeNSViewRef pView)
2994{
2995 COCOA_LOG_FLOW(("cocoaViewDestroy: pView=%p\n", (void *)pView));
2996 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
2997
2998 VBoxMainThreadTaskRunner *pRunner = [VBoxMainThreadTaskRunner globalInstance];
2999 [pRunner addObj:pView selector:@selector(vboxDestroy) arg:nil];
3000
3001 [pPool release];
3002 COCOA_LOG_FLOW(("cocoaViewDestroy: returns\n"));
3003}
3004
3005void cocoaViewShow(NativeNSViewRef pView, GLboolean fShowIt)
3006{
3007 COCOA_LOG_FLOW(("cocoaViewShow: pView=%p fShowIt=%d\n", (void *)pView, fShowIt));
3008 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
3009
3010 [(OverlayView *)pView vboxSetVisible:fShowIt];
3011
3012 [pPool release];
3013 COCOA_LOG_FLOW(("cocoaViewShow: returns\n"));
3014}
3015
3016void cocoaViewDisplay(NativeNSViewRef pView)
3017{
3018 COCOA_LOG_FLOW(("cocoaViewDisplay: pView=%p\n", (void *)pView));
3019 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
3020
3021#ifndef IN_VMSVGA3D
3022 DEBUG_WARN(("cocoaViewDisplay should never happen!\n"));
3023 DEBUG_MSG_1(("cocoaViewDisplay %p\n", (void *)pView));
3024#endif
3025 [(OverlayView *)pView swapFBO];
3026
3027 [pPool release];
3028 COCOA_LOG_FLOW(("cocoaViewDisplay: returns\n"));
3029}
3030
3031void cocoaViewSetPosition(NativeNSViewRef pView, NativeNSViewRef pParentView, int x, int y)
3032{
3033 COCOA_LOG_FLOW(("cocoaViewSetPosition: pView=%p pParentView=%p x=%d y=%d\n", (void *)pView, (void *)pParentView, x, y));
3034 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
3035
3036 [(OverlayView *)pView vboxSetPos:NSMakePoint(x, y)];
3037
3038 [pPool release];
3039 COCOA_LOG_FLOW(("cocoaViewSetPosition: returns\n"));
3040}
3041
3042void cocoaViewSetSize(NativeNSViewRef pView, int cx, int cy)
3043{
3044 COCOA_LOG_FLOW(("cocoaViewSetSize: pView=%p cx=%d cy=%d\n", (void *)pView, cx, cy));
3045 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
3046
3047 [(OverlayView *)pView vboxSetSize:NSMakeSize(cx, cy)];
3048
3049 [pPool release];
3050 COCOA_LOG_FLOW(("cocoaViewSetSize: returns\n"));
3051}
3052
3053#ifndef IN_VMSVGA3D
3054
3055typedef struct CR_RCD_GETGEOMETRY
3056{
3057 OverlayView *pView;
3058 NSRect rect;
3059} CR_RCD_GETGEOMETRY;
3060
3061static DECLCALLBACK(void) vboxRcdGetGeomerty(void *pvUser)
3062{
3063 CR_RCD_GETGEOMETRY *pGetGeometry = (CR_RCD_GETGEOMETRY *)pvUser;
3064 pGetGeometry->rect = [[pGetGeometry->pView window] frame];
3065 COCOA_LOG_FLOW(("vboxRcdGetGeomerty: (x,y)=(%d,%d) (cx,cy)=(%d,%d)\n", pGetGeometry->rect.origin.x, pGetGeometry->rect.origin.y,
3066 pGetGeometry->rect.size.width, pGetGeometry->rect.size.height));
3067}
3068
3069#endif /* !IN_VMSVGA3D */
3070
3071void cocoaViewGetGeometry(NativeNSViewRef pView, int *px, int *py, int *pcx, int *pcy)
3072{
3073 COCOA_LOG_FLOW(("cocoaViewGetGeometry: pView=%p px=%p py=%p pcx=%p pcy=%p\n",
3074 (void *)pView, (void *)px, (void *)py, (void *)pcx, (void *)pcy));
3075 NSAutoreleasePool *pPool;
3076 pPool = [[NSAutoreleasePool alloc] init];
3077
3078 /* make sure all tasks are run, to preserve the order */
3079 VBoxMainThreadTaskRunner *pRunner = [VBoxMainThreadTaskRunner globalInstance];
3080 [pRunner runTasksSyncIfPossible];
3081
3082 NSRect frame;
3083#ifndef IN_VMSVGA3D
3084 if (renderspuCalloutAvailable())
3085 {
3086 CR_RCD_GETGEOMETRY GetGeometry;
3087 GetGeometry.pView = (OverlayView *)pView;
3088 renderspuCalloutClient(vboxRcdGetGeomerty, &GetGeometry);
3089 frame = GetGeometry.rect;
3090 }
3091 else
3092#endif
3093 {
3094 DEBUG_MSG_NOT_VMSVGA3D(("no callout available on getGeometry\n"));
3095 frame = [[pView window] frame];
3096 }
3097
3098 *px = frame.origin.x;
3099 *py = frame.origin.y;
3100 *pcx = frame.size.width;
3101 *pcy = frame.size.height;
3102
3103 [pPool release];
3104 COCOA_LOG_FLOW(("cocoaViewGetGeometry: returns *px=%d, *py=%d, *pcx=%d, *pcy=%d\n", *px, *py, *pcx, *pcy));
3105}
3106
3107void cocoaViewPresentComposition(NativeNSViewRef pView, PCVBOXVR_SCR_COMPOSITOR_ENTRY pChangedEntry)
3108{
3109 COCOA_LOG_FLOW(("cocoaViewPresentComposition: pView=%p pChangedEntry=%p\n", (void *)pView, (void *)pChangedEntry));
3110 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
3111 NSOpenGLContext *pCtx;
3112
3113 /* view should not necesserily have a context set */
3114 pCtx = [(OverlayView *)pView glCtx];
3115 if (!pCtx)
3116 {
3117#ifdef IN_VMSVGA3D /** @todo VMSVGA3 */
3118 pCtx = NULL;
3119#else
3120 ContextInfo *pCtxInfo = renderspuDefaultSharedContextAcquire();
3121 if (!pCtxInfo)
3122 {
3123 DEBUG_WARN(("renderspuDefaultSharedContextAcquire returned NULL"));
3124
3125 [pPool release];
3126 DEBUG_FUNC_LEAVE();
3127 return;
3128 }
3129
3130 pCtx = pCtxInfo->context;
3131#endif
3132
3133 [(OverlayView *)pView setGLCtx:pCtx];
3134 }
3135
3136 [(OverlayView *)pView presentComposition:pChangedEntry];
3137
3138 [pPool release];
3139 COCOA_LOG_FLOW(("cocoaViewPresentComposition: returns\n"));
3140}
3141
3142void cocoaViewMakeCurrentContext(NativeNSViewRef pView, NativeNSOpenGLContextRef pCtx)
3143{
3144 COCOA_LOG_FLOW(("cocoaViewMakeCurrentContext: pView=%p pCtx=%p\n", (void *)pView, (void *)pCtx));
3145 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
3146
3147 if (pView)
3148 {
3149 [(OverlayView *)pView setGLCtx:pCtx];
3150 [(OverlayView *)pView makeCurrentFBO];
3151 }
3152 else
3153 {
3154#ifdef IN_VMSVGA3D
3155 /* Always flush before flush. glXMakeCurrent and wglMakeCurrent does this
3156 implicitly, seemingly NSOpenGLContext::makeCurrentContext doesn't. */
3157 if ([NSOpenGLContext currentContext] != nil)
3158 {
3159 DEBUG_CLEAR_GL_ERRORS();
3160 glFlush();
3161 DEBUG_CHECK_GL_ERROR("glFlush");
3162 }
3163#endif
3164 [NSOpenGLContext clearCurrentContext];
3165 }
3166
3167 [pPool release];
3168 COCOA_LOG_FLOW(("cocoaViewMakeCurrentContext: returns\n"));
3169}
3170
3171GLboolean cocoaViewNeedsEmptyPresent(NativeNSViewRef pView)
3172{
3173 COCOA_LOG_FLOW(("cocoaViewNeedsEmptyPresent: pView=%p\n", (void *)pView));
3174 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
3175
3176 GLboolean fNeedsPresent = [(OverlayView *)pView vboxNeedsEmptyPresent];
3177
3178 [pPool release];
3179 COCOA_LOG_FLOW(("cocoaViewNeedsEmptyPresent: returns %d\n", fNeedsPresent));
3180 return fNeedsPresent;
3181}
3182
3183void cocoaViewSetVisibleRegion(NativeNSViewRef pView, GLint cRects, const GLint *paRects)
3184{
3185 COCOA_LOG_FLOW(("cocoaViewSetVisibleRegion: pView=%p cRects=%d paRects=%p)\n", (void *)pView, cRects, (void const *)paRects));
3186 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
3187
3188 [(OverlayView *)pView setVisibleRegions:cRects paRects:paRects];
3189
3190 [pPool release];
3191 COCOA_LOG_FLOW(("cocoaViewSetVisibleRegion: returns\n"));
3192}
3193
3194
3195#ifdef IN_VMSVGA3D
3196/*
3197 * VMSVGA3D interface.
3198 */
3199
3200VMSVGA3D_DECL(void) vmsvga3dCocoaCreateContext(NativeNSOpenGLContextRef *ppCtx, NativeNSOpenGLContextRef pSharedCtx,
3201 bool fOtherProfile)
3202{
3203 cocoaGLCtxCreate(ppCtx, CR_ALPHA_BIT | CR_DEPTH_BIT | CR_DOUBLE_BIT | (fOtherProfile ? VMSVGA3D_NON_DEFAULT_PROFILE_BIT : 0),
3204 pSharedCtx);
3205}
3206
3207VMSVGA3D_DECL(void) vmsvga3dCocoaDestroyContext(NativeNSOpenGLContextRef pCtx)
3208{
3209 cocoaGLCtxDestroy(pCtx);
3210}
3211
3212VMSVGA3D_DECL(void) vmsvga3dCocoaCreateView(NativeNSViewRef *ppView, NativeNSViewRef pParentView)
3213{
3214 /** @todo share WinInfo with caller and maintain it better. */
3215 WindowInfo *pWinInfo = (WindowInfo *)RTMemAllocZ(sizeof(WindowInfo));
3216 AssertLogRelReturnVoid(pWinInfo);
3217 pWinInfo->cRefs = 1;
3218 RTCritSectInit(&pWinInfo->CompositorLock);
3219
3220 cocoaViewCreate(ppView, pWinInfo, pParentView, 0 /* fVisParams - ignored */);
3221}
3222
3223VMSVGA3D_DECL(void) vmsvga3dCocoaDestroyView(NativeNSViewRef pView)
3224{
3225 cocoaViewDestroy(pView);
3226}
3227
3228VMSVGA3D_DECL(void) vmsvga3dCocoaViewSetPosition(NativeNSViewRef pView, NativeNSViewRef pParentView, int x, int y)
3229{
3230 cocoaViewSetPosition(pView, pParentView, x, y);
3231}
3232
3233VMSVGA3D_DECL(void) vmsvga3dCocoaViewSetSize(NativeNSViewRef pView, int w, int h)
3234{
3235 cocoaViewSetSize(pView, w, h);
3236}
3237
3238VMSVGA3D_DECL(void) vmsvga3dCocoaViewMakeCurrentContext(NativeNSViewRef pView, NativeNSOpenGLContextRef pCtx)
3239{
3240 Assert(!pView || [(OverlayView *)pView glCtx] == pCtx || [(OverlayView *)pView glCtx] == nil);
3241 cocoaViewMakeCurrentContext(pView, pCtx);
3242}
3243
3244VMSVGA3D_DECL(void) vmsvga3dCocoaSwapBuffers(NativeNSViewRef pView, NativeNSOpenGLContextRef pCtx)
3245{
3246# if 1
3247 Assert([(OverlayView *)pView glCtx] == pCtx);
3248 cocoaViewDisplay(pView);
3249# else
3250 DEBUG_FUNC_ENTER();
3251 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
3252
3253 [pCtx flushBuffer];
3254
3255 [pPool release];
3256 DEBUG_FUNC_LEAVE();
3257# endif
3258}
3259
3260#endif /* IN_VMSVGA3D */
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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