VirtualBox

source: vbox/trunk/src/VBox/Devices/Graphics/DevVGA-SVGA3d-cocoa.m@ 61497

Last change on this file since 61497 was 57790, checked in by vboxsync, 9 years ago

VMSVGA3d: Turns out I'm blitting to the wrong end (Y direction) of the nsview framebuffer. Missed some [NSOpenGLContext update] calls when the parent view got resized, so it sometimes worked, but not all the time. After calling update, the visible part of the framebuffer is the bottom half, not the top half as I though and as seems to be the case on the other plaforms.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 32.9 KB
Line 
1/* $Id: DevVGA-SVGA3d-cocoa.m 57790 2015-09-16 17:09:28Z vboxsync $ */
2/** @file
3 * VirtualBox OpenGL Cocoa Window System Helper Implementation.
4 *
5 * @remarks Inspired by HostServices/SharedOpenGL/render/renderspu_cocoa_helper.m.
6 */
7
8/*
9 * Copyright (C) 2009-2015 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20
21/*********************************************************************************************************************************
22* Header Files *
23*********************************************************************************************************************************/
24#define LOG_GROUP LOG_GROUP_DEV_VMSVGA
25#include "DevVGA-SVGA3d-cocoa.h"
26#import <Cocoa/Cocoa.h>
27#undef PVM /* Stupid namespace pollution from outdated sys/param.h header file. */
28#import <OpenGL/gl.h>
29
30#include <iprt/thread.h>
31#include <iprt/assert.h>
32#include <iprt/string.h>
33#include <VBox/log.h>
34#include <VBox/vmm/dbgf.h>
35
36
37/*********************************************************************************************************************************
38* Defined Constants And Macros *
39*********************************************************************************************************************************/
40/** @def USE_NSOPENGLVIEW
41 * Define this to experiment with using NSOpenGLView instead
42 * of NSView. There are transparency issues with the former,
43 * so for the time being we're using the latter. */
44#if 0
45#define USE_NSOPENGLVIEW
46#endif
47
48/**@def FLOAT_FMT_STR
49 * Format string bits to go with FLOAT_FMT_ARGS. */
50#define FLOAT_FMT_STR "%d.%06d"
51/** @def FLOAT_FMT_ARGS
52 * Format arguments for a float value, corresponding to FLOAT_FMT_STR.
53 * @param r The floating point value to format. */
54#define FLOAT_FMT_ARGS(r) (int)(r), ((unsigned)((r) * 1000000) % 1000000U)
55
56
57
58/*********************************************************************************************************************************
59* Structures and Typedefs *
60*********************************************************************************************************************************/
61/**
62 * Argument package for doing this on the main thread.
63 */
64@interface VMSVGA3DCreateViewAndContext : NSObject
65{
66@public
67 /* in */
68 NativeNSViewRef pParentView;
69 uint32_t cx;
70 uint32_t cy;
71 NativeNSOpenGLContextRef pSharedCtx;
72 bool fOtherProfile;
73
74 /* out */
75 NativeNSViewRef pView;
76 NativeNSOpenGLContextRef pCtx;
77}
78@end
79
80
81/**
82 * The overlay view.
83 */
84@interface VMSVGA3DOverlayView
85#ifdef USE_NSOPENGLVIEW
86 : NSOpenGLView
87#else
88 : NSView
89#endif
90{
91@private
92 /** This points to the parent view, if there is one. If there isn't a parent
93 * the view will be hidden and never used for displaying stuff. We only have
94 * one visible context per guest screen that is visible to the user and
95 * subject to buffer swapping. */
96 NSView *m_pParentView;
97 /** Indicates that buffers (back+front) needs clearing before use because
98 * the view changed size. There are two buffers, so this is set to two
99 * each time when the view area increases. */
100 uint32_t m_cClears;
101 /** Set if the OpenGL context needs updating after a resize. */
102 bool m_fUpdateCtx;
103
104#ifndef USE_NSOPENGLVIEW
105 /** The OpenGL context associated with this view. */
106 NSOpenGLContext *m_pCtx;
107 /** Number of times we've tried to set the view (shut up noisy NSLog). */
108 uint32_t m_cSetViewAttempts;
109#endif
110
111 /** The desired view position relative to super. */
112 NSPoint m_Pos;
113 /** The desired view size. */
114 NSSize m_Size;
115}
116+ (void)createViewAndContext:(VMSVGA3DCreateViewAndContext *)pParams;
117- (id)initWithFrameAndFormat:(NSRect)frame parentView:(NSView*)pparentView pixelFormat:(NSOpenGLPixelFormat *)pFmt;
118- (void)vboxSetPos:(NSPoint)pos;
119- (void)vboxSetSize:(NSSize)size;
120- (void)vboxScheduleCtxUpdate;
121- (void)vboxReshapePerform;
122- (void)vboxReshape;
123- (void)vboxBoundsDidChange:(NSNotification *)pNotification;
124- (void)vboxFrameDidChange:(NSNotification *)pNotification;
125- (void)vboxFrameDidChangeGlobal:(NSNotification *)pNotification;
126- (BOOL)postsFrameChangedNotifications;
127- (void)vboxRemoveFromSuperviewAndHide;
128- (void)vboxUpdateCtxIfNecessary;
129- (void)vboxClearBackBufferIfNecessary;
130- (NSOpenGLContext *)makeCurrentGLContext;
131- (void)restoreSavedGLContext:(NSOpenGLContext *)pSavedCtx;
132
133#ifndef USE_NSOPENGLVIEW
134/* NSOpenGLView fakes: */
135- (void)setOpenGLContext:(NSOpenGLContext *)pCtx;
136- (NSOpenGLContext *)openGLContext;
137- (void)prepareOpenGL;
138
139#endif
140/* Overridden: */
141- (void)viewDidMoveToWindow;
142- (void)viewDidMoveToSuperview;
143- (void)resizeWithOldSuperviewSize:(NSSize)oldBoundsSize;
144- (void)drawRect:(NSRect)rect;
145
146@end
147
148
149/********************************************************************************
150*
151* VMSVGA3DOverlayView class implementation
152*
153********************************************************************************/
154@implementation VMSVGA3DOverlayView
155
156
157+ (void)createViewAndContext:(VMSVGA3DCreateViewAndContext *)pParams
158{
159 LogFlow(("OvlView createViewAndContext:\n"));
160
161 /*
162 * Create a pixel format.
163 */
164 NSOpenGLPixelFormat *pFmt = nil;
165
166 // Consider to remove it and check if it's harmless.
167 NSOpenGLPixelFormatAttribute attribs[] =
168 {
169 NSOpenGLPFAOpenGLProfile, (NSOpenGLPixelFormatAttribute)0,
170 //NSOpenGLPFAWindow, - obsolete/deprecated, try work without it...
171 NSOpenGLPFAAccelerated,
172 NSOpenGLPFADoubleBuffer,
173 NSOpenGLPFABackingStore,
174 NSOpenGLPFAColorSize, (NSOpenGLPixelFormatAttribute)24,
175 NSOpenGLPFAAlphaSize, (NSOpenGLPixelFormatAttribute)8,
176 NSOpenGLPFADepthSize, (NSOpenGLPixelFormatAttribute)24,
177 0
178 };
179 attribs[1] = pParams->fOtherProfile ? NSOpenGLProfileVersion3_2Core : NSOpenGLProfileVersionLegacy;
180 pFmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
181 if (pFmt)
182 {
183 /*
184 * Create a new view.
185 */
186 NSRect Frame;
187 Frame.origin.x = 0;
188 Frame.origin.y = 0;
189 Frame.size.width = pParams->cx < _1M && pParams->cx > 0 ? pParams->cx : 1; /* 'invalid drawable' if 0,0 size? */
190 Frame.size.height = pParams->cy < _1M && pParams->cy > 0 ? pParams->cy : 1;
191 VMSVGA3DOverlayView *pView = [[VMSVGA3DOverlayView alloc] initWithFrameAndFormat:Frame
192 parentView:pParams->pParentView
193 pixelFormat:pFmt];
194 if (pView)
195 {
196 /*
197 * If we have no shared GL context, we use the one that NSOpenGLView create. Otherwise,
198 * we replace it. (If we don't call openGLContext, it won't yet have been instantiated,
199 * so there is no unecessary contexts created here when pSharedCtx != NULL.)
200 */
201 NSOpenGLContext *pCtx;
202#ifdef USE_NSOPENGLVIEW
203 if (!pParams->pSharedCtx)
204 pCtx = [pView openGLContext];
205 else
206#endif
207 {
208 pCtx = [[NSOpenGLContext alloc] initWithFormat:pFmt shareContext: pParams->pSharedCtx];
209 if (pCtx)
210 {
211 [pView setOpenGLContext:pCtx];
212 [pCtx setView:pView];
213#ifdef USE_NSOPENGLVIEW
214 Assert([pCtx view] == pView);
215#endif
216 }
217 }
218 if (pCtx)
219 {
220 /*
221 * Attach the view to the parent if we have one. Otherwise make sure its invisible.
222 */
223 if (pParams->pParentView)
224 [pParams->pParentView addSubview:pView];
225 else
226 [pView setHidden:YES];
227
228 /*
229 * Resize and return.
230 */
231 //[pView vboxSetSize:Frame.size];
232
233 NSOpenGLContext *pSavedCtx = [pView makeCurrentGLContext];
234
235 [pView prepareOpenGL];
236 GLint x;
237 //x = 0; [pCtx setValues:&x forParameter:NSOpenGLCPSwapInterval];
238 //x = 1; [pCtx setValues:&x forParameter:NSOpenGLCPSurfaceOrder];
239 x = 0; [pCtx setValues:&x forParameter:NSOpenGLCPSurfaceOpacity];
240
241 if (pParams->pParentView)
242 [pView setHidden:NO];
243 else
244 [pView setHidden:YES];
245
246 [pView restoreSavedGLContext:pSavedCtx];
247
248 pParams->pView = pView;
249 pParams->pCtx = pCtx;
250 [pCtx retain]; //??
251
252 [pFmt release];
253
254 LogFlow(("OvlView createViewAndContext: returns successfully\n"));
255 return;
256 }
257 [pView release];
258 }
259 [pFmt release];
260 }
261 else
262 AssertFailed();
263
264 LogFlow(("OvlView createViewAndContext: returns failure\n"));
265 return;
266}
267
268- (id)initWithFrameAndFormat:(NSRect) frame parentView:(NSView *)pParentView pixelFormat:(NSOpenGLPixelFormat *)pFmt
269{
270 LogFlow(("OvlView(%p) initWithFrameAndFormat:\n", (void *)self));
271
272 m_pParentView = pParentView;
273 /* Make some reasonable defaults */
274 m_Pos = NSZeroPoint;
275 m_Size = frame.size;
276 m_cClears = 2;
277 m_fUpdateCtx = true;
278
279#ifdef USE_NSOPENGLVIEW
280 self = [super initWithFrame:frame pixelFormat:pFmt];
281#else
282 m_cSetViewAttempts = 0;
283 m_pCtx = NULL;
284 self = [super initWithFrame:frame];
285#endif
286 if (self)
287 {
288 //self.autoresizingMask = NSViewMinXMargin | NSViewMaxXMargin | NSViewMinYMargin | NSViewMaxYMargin;
289 self.autoresizingMask = NSViewNotSizable;
290
291 /*
292 * Get notifications when we're moved or resized and when we're moved
293 * to a different screen or GPU or when the GL context simply needs updating.
294 */
295 if (pParentView)
296 {
297 [[NSNotificationCenter defaultCenter] addObserver:self
298 selector:@selector(vboxBoundsDidChange:)
299 name:NSViewBoundsDidChangeNotification
300 object:self];
301 [[NSNotificationCenter defaultCenter] addObserver:self
302 selector:@selector(vboxFrameDidChange:)
303 name:NSViewFrameDidChangeNotification
304 object:self];
305 //[[NSNotificationCenter defaultCenter] addObserver:self
306 // selector:@selector(vboxFrameDidChange:)
307 // name:NSViewDidUpdateTrackingAreasNotification
308 // object:self];
309 [[NSNotificationCenter defaultCenter] addObserver:self
310 selector:@selector(vboxFrameDidChangeGlobal:)
311 name:NSViewGlobalFrameDidChangeNotification
312 object:self];
313 }
314 }
315 LogFlow(("OvlView(%p) initWithFrameAndFormat: returns %p\n", (void *)self, (void *)self));
316 return self;
317}
318
319- (void)dealloc
320{
321 LogFlow(("OvlView(%p) dealloc:\n", (void *)self));
322
323#ifdef USE_NSOPENGLVIEW
324 [[self openGLContext] clearDrawable];
325#else
326 if (m_pCtx)
327 {
328 [m_pCtx clearDrawable];
329 [m_pCtx release];
330 m_pCtx = nil;
331 }
332#endif
333
334 [super dealloc];
335
336 LogFlow(("OvlView(%p) dealloc: returns\n", (void *)self));
337}
338
339
340- (void)vboxSetPos:(NSPoint)pos
341{
342 Log(("OvlView(%p) vboxSetPos: (%d,%d)\n", (void *)self, (int)pos.x, (int)pos.y));
343
344 m_Pos = pos;
345 [self vboxReshape];
346
347 LogFlow(("OvlView(%p) vboxSetPos: returns\n", (void *)self));
348}
349
350
351- (void)vboxSetSize:(NSSize)size
352{
353 Log(("OvlView(%p) vboxSetSize: (%d,%d):\n", (void *)self, (int)size.width, (int)size.height));
354 m_Size = size;
355 [self vboxReshape];
356 LogFlow(("OvlView(%p) vboxSetSize: returns\n", (void *)self));
357}
358
359- (void)vboxScheduleCtxUpdate
360{
361 m_fUpdateCtx = true;
362}
363
364- (void)vboxUpdateCtxIfNecessary
365{
366 if (m_fUpdateCtx)
367 {
368 Log(("OvlView(%p) vboxUpdateCtxIfNecessary: m_fUpdateCtx\n", (void *)self));
369 [[self openGLContext] update];
370 m_fUpdateCtx = false;
371 }
372}
373
374
375- (void)vboxClearBackBufferIfNecessary
376{
377#if 1 /* experiment */
378 if (m_cClears > 0)
379 {
380 Assert(![NSThread isMainThread]);
381 Assert([self openGLContext] == [NSOpenGLContext currentContext]);
382 Log(("OvlView(%p) vboxClearBackBufferIfNecessary: m_cClears=%d\n", (void *)self, m_cClears));
383 m_cClears--;
384
385 /* Clear errors. */
386 GLenum rc;
387 while ((rc = glGetError()) != GL_NO_ERROR)
388 continue;
389
390 /* Save the old buffer setting and make it GL_BACK (shall be GL_BACK already actually). */
391 GLint iOldDrawBuf = GL_BACK;
392 glGetIntegerv(GL_DRAW_BUFFER, &iOldDrawBuf);
393 if (iOldDrawBuf != GL_BACK)
394 glDrawBuffer(GL_BACK);
395 while ((rc = glGetError()) != GL_NO_ERROR)
396 AssertMsgFailed(("rc=%x\n", rc));
397
398 /* Clear the current GL_BACK. */
399 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
400 glClear(GL_COLOR_BUFFER_BIT /*|GL_DEPTH_BUFFER_BIT*/ );
401 while ((rc = glGetError()) != GL_NO_ERROR)
402 AssertMsgFailed(("rc=%x\n", rc));
403
404 /* We're back to the orignal back buffer now. Just restore GL_DRAW_BUFFER. */
405 if (iOldDrawBuf != GL_BACK)
406 glDrawBuffer(iOldDrawBuf);
407
408 while ((rc = glGetError()) != GL_NO_ERROR)
409 AssertMsgFailed(("rc=%x\n", rc));
410 }
411#endif
412}
413
414
415
416- (void)vboxReshapePerform
417{
418 /*
419 * Change the size and position if necessary.
420 */
421 NSRect CurFrameRect = [self frame];
422 /** @todo conversions? */
423 if ( m_Pos.x != CurFrameRect.origin.x
424 || m_Pos.y != CurFrameRect.origin.y)
425 {
426 LogFlow(("OvlView(%p) vboxReshapePerform: moving (%d,%d) -> (%d,%d)\n",
427 (void *)self, CurFrameRect.origin.x, CurFrameRect.origin.y, m_Pos.x, m_Pos.y));
428 [self setFrameOrigin:m_Pos];
429 }
430
431 if ( CurFrameRect.size.width != m_Size.width
432 || CurFrameRect.size.height != m_Size.height)
433 {
434 LogFlow(("OvlView(%p) vboxReshapePerform: resizing (%d,%d) -> (%d,%d)\n",
435 (void *)self, CurFrameRect.size.width, CurFrameRect.size.height, m_Size.width, m_Size.height));
436 [self setFrameSize:m_Size];
437
438 /*
439 * Schedule two clears and a context update for now.
440 * Really though, we should just clear any new surface area.
441 */
442 m_cClears = 2;
443 }
444 m_fUpdateCtx = true;
445 LogFlow(("OvlView(%p) vboxReshapePerform: returns\n", self));
446}
447
448
449- (void)vboxReshape
450{
451 LogFlow(("OvlView(%p) vboxReshape:\n", (void *)self));
452
453 /*
454 * Resize the view.
455 */
456 if ([NSThread isMainThread])
457 [self vboxReshapePerform];
458 else
459 {
460 [self performSelectorOnMainThread:@selector(vboxReshapePerform) withObject:nil waitUntilDone:NO];
461 vmsvga3dCocoaServiceRunLoop();
462
463 /*
464 * Try update the opengl context.
465 */
466 [[self openGLContext] update];
467 }
468
469 LogFlow(("OvlView(%p) vboxReshape: returns\n", (void *)self));
470}
471
472/**
473 * This is called when the bounds change.
474 *
475 * We indicate that the FIFO thread must update the GL context.
476 */
477- (void)vboxBoundsDidChange:(NSNotification *)pNotification
478{
479 LogFlow(("OvlView(%p) vboxBoundsDidChange:\n", (void *)self));
480 self->m_fUpdateCtx = true;
481}
482
483/**
484 * This is called when the frame changes size or position.
485 *
486 * We indicate that the FIFO thread must update the GL context.
487 */
488- (void)vboxFrameDidChange:(NSNotification *)pNotification
489{
490 LogFlow(("OvlView(%p) vboxFrameDidChange:\n", (void *)self));
491 self->m_fUpdateCtx = true;
492}
493
494/**
495 * This is called when moved to different screen/GPU or/and when the GL context
496 * needs updating.
497 *
498 * We indicate that the FIFO thread must update the GL context.
499 */
500- (void)vboxFrameDidChangeGlobal:(NSNotification *)pNotification
501{
502 LogFlow(("OvlView(%p) vboxFrameDidChangeGlobal:\n", (void *)self));
503 self->m_fUpdateCtx = true;
504}
505
506/** This enables the vboxFrameDidChange notification. */
507- (BOOL)postsFrameChangedNotifications
508{
509 LogFlow(("OvlView(%p) postsFrameChangedNotifications:\n", (void *)self));
510 return YES;
511}
512
513/**
514 * Removes the view from the parent, if it has one, and makes sure it's hidden.
515 *
516 * This is callbed before destroying it.
517 */
518- (void)vboxRemoveFromSuperviewAndHide
519{
520 LogFlow(("OvlView(%p) vboxRemoveFromSuperviewAndHide:\n", (void *)self));
521 if (m_pParentView)
522 {
523 /*
524 * The removeFromSuperview has been frequently seen to deadlock thing like this:
525 * #0 0x00007fff8db440fa in __psynch_cvwait ()
526 * #1 0x00007fff8d0acfb9 in _pthread_cond_wait ()
527 * #2 0x00007fff8a1bc8f0 in -[NSViewHierarchyLock _lockForWriting:handler:] ()
528 * #3 0x00007fff8a1bc171 in -[NSView removeFromSuperview] ()
529 * #4 0x000000010cffb2bb in -[VMSVGA3DOverlayView vboxRemoveFromSuperviewAndHide] (self=0x10a1da550, _cmd=0x10cffd734) at DevVGA-SVGA3d-cocoa.m:467
530 * #5 0x000000010cffbed3 in vmsvga3dCocoaDestroyViewAndContext (pView=0x10a1da550, pCtx=0x10a1da630) at DevVGA-SVGA3d-cocoa.m:662
531 * (This is from OS X 10.8.5.)
532 */
533 if ([NSThread isMainThread])
534 {
535 LogFlow(("OvlView(%p) vboxRemoveFromSuperviewAndHide: calling removeFromSuperview\n", (void *)self));
536 [self removeFromSuperview];
537 LogFlow(("OvlView(%p) vboxRemoveFromSuperviewAndHide: calling setHidden\n", (void *)self));
538 [self setHidden:YES];
539 LogFlow(("OvlView(%p) vboxRemoveFromSuperviewAndHide: calling setHidden\n", (void *)self));
540 [[NSNotificationCenter defaultCenter] removeObserver:self];
541 }
542 else
543 {
544 LogFlow(("OvlView(%p) vboxRemoveFromSuperviewAndHide: defering to main thread\n", (void *)self));
545 vmsvga3dCocoaServiceRunLoop();
546 [self performSelectorOnMainThread:@selector(vboxRemoveFromSuperviewAndHide) withObject:nil waitUntilDone:YES];
547 vmsvga3dCocoaServiceRunLoop();
548 LogFlow(("OvlView(%p) vboxRemoveFromSuperviewAndHide: main thread done\n", (void *)self));
549 }
550 }
551}
552
553
554/**
555 * Changes to the OpenGL context associated with the view.
556 * @returns Previous OpenGL context.
557 */
558- (NSOpenGLContext *)makeCurrentGLContext
559{
560 NSOpenGLContext *pSavedCtx = [NSOpenGLContext currentContext];
561
562 /* Always flush before changing. glXMakeCurrent and wglMakeCurrent does this
563 implicitly, seemingly NSOpenGLContext::makeCurrentContext doesn't. */
564 if (pSavedCtx != nil)
565 glFlush();
566
567 [[self openGLContext] makeCurrentContext];
568 return pSavedCtx;
569}
570
571
572/**
573 * Restores the previous OpenGL context after
574 * makeCurrentGLContext.
575 *
576 * @param pSavedCtx The makeCurrentGLContext return value.
577 */
578- (void)restoreSavedGLContext:(NSOpenGLContext *)pSavedCtx
579{
580 /* Always flush before changing. glXMakeCurrent and wglMakeCurrent does this
581 implicitly, seemingly NSOpenGLContext::makeCurrentContext doesn't. */
582 glFlush();
583
584 if (pSavedCtx)
585 [pSavedCtx makeCurrentContext];
586 else
587 [NSOpenGLContext clearCurrentContext];
588}
589
590#ifndef USE_NSOPENGLVIEW
591/*
592 * Faking NSOpenGLView interface.
593 */
594- (void)setOpenGLContext:(NSOpenGLContext *)pCtx
595{
596 if (pCtx != m_pCtx)
597 {
598 if (pCtx)
599 {
600 [pCtx retain];
601 [pCtx setView:self];
602 /*Assert([pCtx view] == self); - setView fails early on, works later... */
603 }
604
605 if (m_pCtx)
606 [m_pCtx release];
607
608 m_pCtx = pCtx;
609
610 if (pCtx)
611 [pCtx update];
612 }
613}
614
615- (NSOpenGLContext *)openGLContext
616{
617 /* Stupid hacks to work around setView failing early. This can get kind of
618 noisy on some OS versions, so shut it up a little bit. */
619 /** @todo use NSOpenGLView for the non-visible contexts. */
620 if (m_pCtx && [m_pCtx view] != self)
621 {
622 m_cSetViewAttempts++;
623 if ( m_pParentView
624 || m_cSetViewAttempts < 64
625 || (m_cSetViewAttempts & (m_cSetViewAttempts < _64K ? 0xfff : 0x7fff)) == 0 )
626 [m_pCtx setView:self];
627 }
628 return m_pCtx;
629}
630
631- (void)prepareOpenGL
632{
633 //[m_pCtx prepareOpenGL];
634}
635#endif /* USE_NSOPENGLVIEW */
636
637/*
638 * Overridden NSOpenGLView / NSView methods:
639 */
640
641/** @todo do we need this? */
642-(void)viewDidMoveToWindow
643{
644 LogFlow(("OvlView(%p) viewDidMoveToWindow: new win: %p\n", (void *)self, (void *)[self window]));
645 [super viewDidMoveToWindow];
646 [self vboxReshape];
647}
648
649-(void)viewDidMoveToSuperview
650{
651 LogFlow(("OvlView(%p) viewDidMoveToSuperview: new view: %p\n", (void *)self, (void *)[self superview]));
652 [super viewDidMoveToSuperview];
653 [self vboxReshape];
654}
655
656-(void)resizeWithOldSuperviewSize:(NSSize)oldBoundsSize
657{
658 LogFlow(("OvlView(%p) resizeWithOldSuperviewSize: %d,%d -> %d,%d\n", (void *)self,
659 (int)oldBoundsSize.width, (int)oldBoundsSize.height, (int)[self bounds].size.width, (int)[self bounds].size.height));
660 [super resizeWithOldSuperviewSize:oldBoundsSize];
661 [self vboxReshape];
662}
663
664- (void)drawRect:(NSRect)rect
665{
666// if (m_fClear)
667// {
668// m_fClear = false;
669// [self vboxClearBuffers];
670// }
671}
672
673@end /* VMSVGA3DOverlayView */
674
675@implementation VMSVGA3DCreateViewAndContext
676@end
677
678
679VMSVGA3DCOCOA_DECL(void) vmsvga3dCocoaServiceRunLoop(void)
680{
681 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
682 NSRunLoop *pRunLoop = [NSRunLoop currentRunLoop];
683
684 if ([NSRunLoop mainRunLoop] != pRunLoop)
685 {
686 [pRunLoop runUntilDate:[NSDate distantPast]];
687 }
688
689 [pPool release];
690}
691
692
693/**
694 * Document me later.
695 *
696 * @param pParentView The parent view if this is a context we'll be
697 * presenting to.
698 */
699VMSVGA3DCOCOA_DECL(bool) vmsvga3dCocoaCreateViewAndContext(NativeNSViewRef *ppView, NativeNSOpenGLContextRef *ppCtx,
700 NativeNSViewRef pParentView, uint32_t cx, uint32_t cy,
701 NativeNSOpenGLContextRef pSharedCtx, bool fOtherProfile)
702{
703 LogFlow(("vmsvga3dCocoaCreateViewAndContext: pParentView=%d size=%d,%d pSharedCtx=%p fOtherProfile=%RTbool\n",
704 (void *)pParentView, cx, cy, (void *)pSharedCtx, fOtherProfile));
705 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
706 vmsvga3dCocoaServiceRunLoop();
707
708
709 VMSVGA3DCreateViewAndContext *pParams = [VMSVGA3DCreateViewAndContext alloc];
710 pParams->pParentView = pParentView;
711 pParams->cx = cx;
712 pParams->cy = cy;
713 pParams->pSharedCtx = pSharedCtx;
714 pParams->fOtherProfile = fOtherProfile;
715 pParams->pView = NULL;
716 pParams->pCtx = NULL;
717
718 [VMSVGA3DOverlayView performSelectorOnMainThread:@selector(createViewAndContext:)
719 withObject:pParams
720 waitUntilDone:YES];
721
722 vmsvga3dCocoaServiceRunLoop();
723
724 *ppCtx = pParams->pCtx;
725 *ppView = pParams->pView;
726 bool fRet = *ppCtx != NULL && *ppView != NULL;
727
728 [pParams release];
729
730 [pPool release];
731 LogFlow(("vmsvga3dCocoaDestroyContext: returns %RTbool\n", fRet));
732 return fRet;
733}
734
735
736VMSVGA3DCOCOA_DECL(void) vmsvga3dCocoaDestroyViewAndContext(NativeNSViewRef pView, NativeNSOpenGLContextRef pCtx)
737{
738 LogFlow(("vmsvga3dCocoaDestroyViewAndContext: pView=%p pCtx=%p\n", (void *)pView, (void *)pCtx));
739 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
740
741 /* The view */
742 VMSVGA3DOverlayView *pOvlView = (VMSVGA3DOverlayView *)pView;
743 [pOvlView vboxRemoveFromSuperviewAndHide];
744
745 Log(("vmsvga3dCocoaDestroyViewAndContext: view %p ref count=%d\n", (void *)pOvlView, [pOvlView retainCount]));
746 [pOvlView release];
747
748 /* The OpenGL context. */
749 Log(("vmsvga3dCocoaDestroyViewAndContext: ctx %p ref count=%d\n", (void *)pCtx, [pCtx retainCount]));
750 [pCtx release];
751
752 [pPool release];
753 LogFlow(("vmsvga3dCocoaDestroyViewAndContext: returns\n"));
754}
755
756
757VMSVGA3DCOCOA_DECL(void) vmsvga3dCocoaViewInfo(PCDBGFINFOHLP pHlp, NativeNSViewRef pView)
758{
759 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
760 if (pView != nil)
761 {
762 VMSVGA3DOverlayView *pOvlView = (VMSVGA3DOverlayView *)pView;
763
764 NSRect FrameRect = [pOvlView frame];
765 pHlp->pfnPrintf(pHlp, " Frame rect: x=" FLOAT_FMT_STR ", y=" FLOAT_FMT_STR " cx=" FLOAT_FMT_STR ", cy=" FLOAT_FMT_STR "\n",
766 FLOAT_FMT_ARGS(FrameRect.origin.x), FLOAT_FMT_ARGS(FrameRect.origin.y),
767 FLOAT_FMT_ARGS(FrameRect.size.width), FLOAT_FMT_ARGS(FrameRect.size.height));
768 NSRect BoundsRect = [pOvlView bounds];
769 pHlp->pfnPrintf(pHlp, " Bounds rect: x=" FLOAT_FMT_STR ", y=" FLOAT_FMT_STR " cx=" FLOAT_FMT_STR ", cy=" FLOAT_FMT_STR "\n",
770 FLOAT_FMT_ARGS(BoundsRect.origin.x), FLOAT_FMT_ARGS(BoundsRect.origin.y),
771 FLOAT_FMT_ARGS(BoundsRect.size.width), FLOAT_FMT_ARGS(BoundsRect.size.height));
772 NSRect VisibleRect = [pOvlView visibleRect];
773 pHlp->pfnPrintf(pHlp, " Visible rect: x=" FLOAT_FMT_STR ", y=" FLOAT_FMT_STR " cx=" FLOAT_FMT_STR ", cy=" FLOAT_FMT_STR "\n",
774 FLOAT_FMT_ARGS(VisibleRect.origin.x), FLOAT_FMT_ARGS(VisibleRect.origin.y),
775 FLOAT_FMT_ARGS(VisibleRect.size.width), FLOAT_FMT_ARGS(VisibleRect.size.height));
776 pHlp->pfnPrintf(pHlp, " isHidden: %RTbool\n", [pOvlView isHidden] != NO);
777 pHlp->pfnPrintf(pHlp, " canDraw: %RTbool\n", [pOvlView canDraw] != NO);
778 pHlp->pfnPrintf(pHlp, " wantsDefaultClipping: %RTbool\n", [pOvlView wantsDefaultClipping] != NO);
779 pHlp->pfnPrintf(pHlp, " wantsLayer: %RTbool\n", [pOvlView wantsLayer] != NO);
780 if ([pOvlView layer] != nil)
781 pHlp->pfnPrintf(pHlp, " Layer: %p\n", [pOvlView layer] != nil);
782 pHlp->pfnPrintf(pHlp, " isOpaque: %RTbool\n", [pOvlView isOpaque] != NO);
783 pHlp->pfnPrintf(pHlp, " autoresizingMask: %#x\n", [pOvlView autoresizingMask]);
784 pHlp->pfnPrintf(pHlp, " isRotatedOrScaledFromBase: %RTbool\n", [pOvlView isRotatedOrScaledFromBase] != NO);
785
786 NSView *pEnclosingScrollView = [pOvlView enclosingScrollView];
787 NSView *pCurView = [pOvlView superview];
788 uint32_t iLevel;
789 for (iLevel = 1; pCurView && iLevel < 7; iLevel++)
790 {
791 NSView *pNextView = [pCurView superview];
792 pHlp->pfnPrintf(pHlp, " Superview#%u: %p, super=%p\n", iLevel, pCurView, pNextView);
793 FrameRect = [pCurView frame];
794 pHlp->pfnPrintf(pHlp, " Superview#%u frame: x=" FLOAT_FMT_STR ", y=" FLOAT_FMT_STR " cx=" FLOAT_FMT_STR ", cy=" FLOAT_FMT_STR "\n",
795 iLevel,
796 FLOAT_FMT_ARGS(FrameRect.origin.x), FLOAT_FMT_ARGS(FrameRect.origin.y),
797 FLOAT_FMT_ARGS(FrameRect.size.width), FLOAT_FMT_ARGS(FrameRect.size.height));
798 BoundsRect = [pCurView bounds];
799 pHlp->pfnPrintf(pHlp, " Superview#%u bounds: x=" FLOAT_FMT_STR ", y=" FLOAT_FMT_STR " cx=" FLOAT_FMT_STR ", cy=" FLOAT_FMT_STR "\n",
800 iLevel,
801 FLOAT_FMT_ARGS(BoundsRect.origin.x), FLOAT_FMT_ARGS(BoundsRect.origin.y),
802 FLOAT_FMT_ARGS(BoundsRect.size.width), FLOAT_FMT_ARGS(BoundsRect.size.height));
803 if (pEnclosingScrollView == pCurView)
804 pHlp->pfnPrintf(pHlp, " Superview#%u is enclosing scroll view\n", iLevel);
805 if ([pCurView enclosingScrollView])
806 pHlp->pfnPrintf(pHlp, " Superview#%u has an enclosing scroll view: %p\n", [pCurView enclosingScrollView]);
807 pCurView = pNextView;
808 }
809 if (pCurView)
810 pHlp->pfnPrintf(pHlp, " (There are more super views)\n");
811
812 NSWindow *pWindow = [pOvlView window];
813 if (pWindow != nil)
814 {
815 pHlp->pfnPrintf(pHlp, " Window: %p\n", pWindow);
816 FrameRect = [pWindow frame];
817 pHlp->pfnPrintf(pHlp, " Window frame: x=" FLOAT_FMT_STR ", y=" FLOAT_FMT_STR " cx=" FLOAT_FMT_STR ", cy=" FLOAT_FMT_STR "\n",
818 FLOAT_FMT_ARGS(FrameRect.origin.x), FLOAT_FMT_ARGS(FrameRect.origin.y),
819 FLOAT_FMT_ARGS(FrameRect.size.width), FLOAT_FMT_ARGS(FrameRect.size.height));
820 CGFloat rFactor = [pWindow backingScaleFactor];
821 pHlp->pfnPrintf(pHlp, " W.backingScaleFactor: " FLOAT_FMT_STR "\n", FLOAT_FMT_ARGS(rFactor));
822 }
823
824 }
825 [pPool release];
826}
827
828
829/** @note Not currently used. */
830VMSVGA3DCOCOA_DECL(void) vmsvga3dCocoaViewSetPosition(NativeNSViewRef pView, NativeNSViewRef pParentView, int x, int y)
831{
832 LogFlow(("vmsvga3dCocoaViewSetPosition: pView=%p pParentView=%p (%d,%d)\n", (void *)pView, (void *)pParentView, x, y));
833 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
834
835 [(VMSVGA3DOverlayView *)pView vboxSetPos:NSMakePoint(x, y)];
836
837 [pPool release];
838 LogFlow(("vmsvga3dCocoaViewSetPosition: returns\n"));
839}
840
841
842VMSVGA3DCOCOA_DECL(void) vmsvga3dCocoaViewUpdateViewport(NativeNSViewRef pView)
843{
844 LogFlow(("vmsvga3dCocoaViewSetSize: pView=%p\n", (void *)pView));
845 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
846 VMSVGA3DOverlayView *pOverlayView = (VMSVGA3DOverlayView *)pView;
847
848 /* Possible that we don't actually need to do this (i.e. this API), but right now I'm
849 leaving it to be sure things actually work right when scrolling. */
850 [pOverlayView vboxScheduleCtxUpdate];
851
852 [pPool release];
853 LogFlow(("vmsvga3dCocoaViewSetSize: returns\n"));
854}
855
856
857VMSVGA3DCOCOA_DECL(void) vmsvga3dCocoaViewSetSize(NativeNSViewRef pView, int cx, int cy)
858{
859 LogFlow(("vmsvga3dCocoaViewSetSize: pView=%p (%d,%d)\n", (void *)pView, cx, cy));
860 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
861 VMSVGA3DOverlayView *pOverlayView = (VMSVGA3DOverlayView *)pView;
862
863 [pOverlayView vboxSetSize:NSMakeSize(cx, cy)];
864
865 [pPool release];
866 LogFlow(("vmsvga3dCocoaViewSetSize: returns\n"));
867}
868
869
870void vmsvga3dCocoaViewMakeCurrentContext(NativeNSViewRef pView, NativeNSOpenGLContextRef pCtx)
871{
872 LogFlow(("vmsvga3dCocoaViewMakeCurrentContext: pView=%p, pCtx=%p\n", (void*)pView, (void*)pCtx));
873 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
874 VMSVGA3DOverlayView *pOverlayView = (VMSVGA3DOverlayView *)pView;
875
876 /* Always flush before flush. glXMakeCurrent and wglMakeCurrent does this
877 implicitly, seemingly NSOpenGLContext::makeCurrentContext doesn't. */
878 if ([NSOpenGLContext currentContext] != 0)
879 glFlush();
880
881 if (pOverlayView)
882 {
883 /* This must be a release assertion as we depend on the setView
884 sideeffect of the openGLContext method call. (hack alert!) */
885 AssertRelease([pOverlayView openGLContext] == pCtx);
886 [pCtx makeCurrentContext];
887 [pOverlayView vboxUpdateCtxIfNecessary];
888 }
889 else
890 [NSOpenGLContext clearCurrentContext];
891
892 [pPool release];
893 LogFlow(("vmsvga3dCocoaViewMakeCurrentContext: returns\n"));
894}
895
896
897void vmsvga3dCocoaSwapBuffers(NativeNSViewRef pView, NativeNSOpenGLContextRef pCtx)
898{
899 LogFlow(("vmsvga3dCocoaSwapBuffers: pView=%p, pCtx=%p\n", (void*)pView, (void*)pCtx));
900 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
901 VMSVGA3DOverlayView *pMyView = (VMSVGA3DOverlayView *)pView;
902
903#ifndef USE_NSOPENGLVIEW
904 /* Hack alert! setView fails early on so call openGLContext to try again. */
905 if ([pCtx view] == NULL)
906 [pMyView openGLContext];
907#endif
908
909 Assert(pCtx == [NSOpenGLContext currentContext]);
910 Assert(pCtx == [pMyView openGLContext]);
911 AssertMsg([pCtx view] == pMyView, ("%p != %p\n", (void *)[pCtx view], (void *)pMyView));
912
913 [pCtx flushBuffer];
914 //[pView setNeedsDisplay:YES];
915 vmsvga3dCocoaServiceRunLoop();
916
917 /* If buffer clearing or/and context updates are pending, execute that now. */
918 [pMyView vboxUpdateCtxIfNecessary];
919 [pMyView vboxClearBackBufferIfNecessary];
920
921 [pPool release];
922 LogFlow(("vmsvga3dCocoaSwapBuffers: returns\n"));
923}
924
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