VirtualBox

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

Last change on this file since 78425 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

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

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