VirtualBox

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

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

VMSVGA3d: Some more cleanups.

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