VirtualBox

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

Last change on this file since 56301 was 56276, checked in by vboxsync, 9 years ago

Host 3D: turn off excessing crDebug() message in Cocoa backend.

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