VirtualBox

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

Last change on this file since 51349 was 50412, checked in by vboxsync, 11 years ago

crOpenGL: scaling bugfixes; rename stretch -> scale

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 60.1 KB
Line 
1/* $Id: renderspu_cocoa_helper.m 50412 2014-02-11 10:21:01Z vboxsync $ */
2/** @file
3 * VirtualBox OpenGL Cocoa Window System Helper Implementation.
4 */
5
6/*
7 * Copyright (C) 2009-2012 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include "renderspu_cocoa_helper.h"
19
20#import <Cocoa/Cocoa.h>
21#undef PVM
22
23#include "chromium.h" /* For the visual bits of chromium */
24
25#include <iprt/thread.h>
26#include <iprt/string.h>
27#include <iprt/mem.h>
28#include <iprt/time.h>
29#include <iprt/assert.h>
30
31#include <cr_vreg.h>
32#include <cr_error.h>
33#include <cr_blitter.h>
34#ifdef VBOX_WITH_CRDUMPER_THUMBNAIL
35# include <cr_pixeldata.h>
36#endif
37
38
39#include "renderspu.h"
40
41/** @page pg_opengl_cocoa OpenGL - Cocoa Window System Helper
42 *
43 * How this works:
44 * In general it is not so easy like on the other platforms, cause Cocoa
45 * doesn't support any clipping of already painted stuff. In Mac OS X there is
46 * the concept of translucent canvas's e.g. windows and there it is just
47 * painted what should be visible to the user. Unfortunately this isn't the
48 * concept of chromium. Therefor I reroute all OpenGL operation from the guest
49 * to a frame buffer object (FBO). This is a OpenGL extension, which is
50 * supported by all OS X versions we support (AFAIC tell). Of course the guest
51 * doesn't know that and we have to make sure that the OpenGL state always is
52 * in the right state to paint into the FBO and not to the front/back buffer.
53 * Several functions below (like cocoaBindFramebufferEXT, cocoaGetIntegerv,
54 * ...) doing this. When a swap or finish is triggered by the guest, the
55 * content (which is already bound to an texture) is painted on the screen
56 * within a separate OpenGL context. This allows the usage of the same
57 * resources (texture ids, buffers ...) but at the same time having an
58 * different internal OpenGL state. Another advantage is that we can paint a
59 * thumbnail of the current output in a much more smaller (GPU accelerated
60 * scale) version on a third context and use glReadPixels to get the actual
61 * data. glReadPixels is a very slow operation, but as we just use a much more
62 * smaller image, we can handle it (anyway this is only done 5 times per
63 * second).
64 *
65 * Other things to know:
66 * - If the guest request double buffering, we have to make sure there are two
67 * buffers. We use the same FBO with 2 color attachments. Also glDrawBuffer
68 * and glReadBuffer is intercepted to make sure it is painted/read to/from
69 * the correct buffers. On swap our buffers are swapped and not the
70 * front/back buffer.
71 * - If the guest request a depth/stencil buffer, a combined render buffer for
72 * this is created.
73 * - If the size of the guest OpenGL window changes, all FBO's, textures, ...
74 * need to be recreated.
75 * - We need to track any changes to the parent window
76 * (create/destroy/move/resize). The various classes like OverlayHelperView,
77 * OverlayWindow, ... are there for.
78 * - The HGCM service runs on a other thread than the Main GUI. Keeps this
79 * always in mind (see e.g. performSelectorOnMainThread in renderFBOToView)
80 * - We make heavy use of late binding. We can not be sure that the GUI (or any
81 * other third party GUI), overwrite our NSOpenGLContext. So we always ask if
82 * this is our own one, before use. Really neat concept of Objective-C/Cocoa
83 * ;)
84 */
85
86/* Debug macros */
87#define FBO 1 /* Disable this to see how the output is without the FBO in the middle of the processing chain. */
88#if 0
89# define CR_RENDER_FORCE_PRESENT_MAIN_THREAD /* force present schedule to main thread */
90# define SHOW_WINDOW_BACKGROUND 1 /* Define this to see the window background even if the window is clipped */
91# define DEBUG_VERBOSE /* Define this to get some debug info about the messages flow. */
92#endif
93
94#ifdef DEBUG_misha
95# define DEBUG_MSG(text) \
96 printf text
97# define DEBUG_WARN(text) do { \
98 crWarning text ; \
99 Assert(0); \
100 } while (0)
101#else
102# define DEBUG_MSG(text) \
103 do {} while (0)
104# define DEBUG_WARN(text) do { \
105 crWarning text ; \
106 } while (0)
107#endif
108
109#ifdef DEBUG_VERBOSE
110# define DEBUG_MSG_1(text) \
111 DEBUG_MSG(text)
112#else
113# define DEBUG_MSG_1(text) \
114 do {} while (0)
115#endif
116
117#ifdef DEBUG_poetzsch
118# define CHECK_GL_ERROR()\
119 do \
120 { \
121 checkGLError(__FILE__, __LINE__); \
122 }while (0);
123
124 static void checkGLError(char *file, int line)
125 {
126 GLenum g = glGetError();
127 if (g != GL_NO_ERROR)
128 {
129 char *errStr;
130 switch (g)
131 {
132 case GL_INVALID_ENUM: errStr = RTStrDup("GL_INVALID_ENUM"); break;
133 case GL_INVALID_VALUE: errStr = RTStrDup("GL_INVALID_VALUE"); break;
134 case GL_INVALID_OPERATION: errStr = RTStrDup("GL_INVALID_OPERATION"); break;
135 case GL_STACK_OVERFLOW: errStr = RTStrDup("GL_STACK_OVERFLOW"); break;
136 case GL_STACK_UNDERFLOW: errStr = RTStrDup("GL_STACK_UNDERFLOW"); break;
137 case GL_OUT_OF_MEMORY: errStr = RTStrDup("GL_OUT_OF_MEMORY"); break;
138 case GL_TABLE_TOO_LARGE: errStr = RTStrDup("GL_TABLE_TOO_LARGE"); break;
139 default: errStr = RTStrDup("UNKNOWN"); break;
140 }
141 DEBUG_MSG(("%s:%d: glError %d (%s)\n", file, line, g, errStr));
142 RTMemFree(errStr);
143 }
144 }
145#else
146# define CHECK_GL_ERROR()\
147 do {} while (0)
148#endif
149
150#define GL_SAVE_STATE \
151 do \
152 { \
153 glPushAttrib(GL_ALL_ATTRIB_BITS); \
154 glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS); \
155 glMatrixMode(GL_PROJECTION); \
156 glPushMatrix(); \
157 glMatrixMode(GL_TEXTURE); \
158 glPushMatrix(); \
159 glMatrixMode(GL_COLOR); \
160 glPushMatrix(); \
161 glMatrixMode(GL_MODELVIEW); \
162 glPushMatrix(); \
163 } \
164 while(0);
165
166#define GL_RESTORE_STATE \
167 do \
168 { \
169 glMatrixMode(GL_MODELVIEW); \
170 glPopMatrix(); \
171 glMatrixMode(GL_COLOR); \
172 glPopMatrix(); \
173 glMatrixMode(GL_TEXTURE); \
174 glPopMatrix(); \
175 glMatrixMode(GL_PROJECTION); \
176 glPopMatrix(); \
177 glPopClientAttrib(); \
178 glPopAttrib(); \
179 } \
180 while(0);
181
182static NSOpenGLContext * vboxCtxGetCurrent()
183{
184 GET_CONTEXT(pCtxInfo);
185 if (pCtxInfo)
186 {
187 Assert(pCtxInfo->context);
188 return pCtxInfo->context;
189 }
190
191 return nil;
192}
193
194static bool vboxCtxSyncCurrentInfo()
195{
196 GET_CONTEXT(pCtxInfo);
197 NSOpenGLContext *pCtx = [NSOpenGLContext currentContext];
198 NSView *pView = pCtx ? [pCtx view] : nil;
199 bool fAdjusted = false;
200 if (pCtxInfo)
201 {
202 WindowInfo *pWinInfo = pCtxInfo->currentWindow;
203 Assert(pWinInfo);
204 if (pCtxInfo->context != pCtx
205 || pWinInfo->window != pView)
206 {
207 renderspu_SystemMakeCurrent(pWinInfo, 0, pCtxInfo);
208 fAdjusted = true;
209 }
210 }
211 else
212 {
213 if (pCtx)
214 {
215 [NSOpenGLContext clearCurrentContext];
216 fAdjusted = true;
217 }
218 }
219
220 return fAdjusted;
221}
222
223typedef struct VBOX_CR_RENDER_CTX_INFO
224{
225 bool fIsValid;
226 NSOpenGLContext *pCtx;
227 NSView *pView;
228} VBOX_CR_RENDER_CTX_INFO, *PVBOX_CR_RENDER_CTX_INFO;
229
230static void vboxCtxEnter(NSOpenGLContext*pCtx, PVBOX_CR_RENDER_CTX_INFO pCtxInfo)
231{
232 NSOpenGLContext *pOldCtx = vboxCtxGetCurrent();
233 NSView *pOldView = (pOldCtx ? [pOldCtx view] : nil);
234 NSView *pView = [pCtx view];
235 bool fNeedCtxSwitch = (pOldCtx != pCtx || pOldView != pView);
236 Assert(pCtx);
237 // Assert(pOldCtx == m_pGLCtx);
238 // Assert(pOldView == self);
239 // Assert(fNeedCtxSwitch);
240 if (fNeedCtxSwitch)
241 {
242 if(pOldCtx != nil)
243 glFlush();
244
245 [pCtx makeCurrentContext];
246
247 pCtxInfo->fIsValid = true;
248 pCtxInfo->pCtx = pOldCtx;
249 pCtxInfo->pView = pView;
250 }
251 else
252 {
253 pCtxInfo->fIsValid = false;
254 }
255}
256
257static void vboxCtxLeave(PVBOX_CR_RENDER_CTX_INFO pCtxInfo)
258{
259 if (pCtxInfo->fIsValid)
260 {
261 NSOpenGLContext *pOldCtx = pCtxInfo->pCtx;
262 NSView *pOldView = pCtxInfo->pView;
263
264 glFlush();
265 if (pOldCtx != nil)
266 {
267 if ([pOldCtx view] != pOldView)
268 {
269 [pOldCtx setView: pOldView];
270 }
271
272 [pOldCtx makeCurrentContext];
273
274#ifdef DEBUG
275 {
276 NSOpenGLContext *pTstOldCtx = [NSOpenGLContext currentContext];
277 NSView *pTstOldView = (pTstOldCtx ? [pTstOldCtx view] : nil);
278 Assert(pTstOldCtx == pOldCtx);
279 Assert(pTstOldView == pOldView);
280 }
281#endif
282 }
283 else
284 {
285 [NSOpenGLContext clearCurrentContext];
286 }
287 }
288}
289
290/** Custom OpenGL context class.
291 *
292 * This implementation doesn't allow to set a view to the
293 * context, but save the view for later use. Also it saves a copy of the
294 * pixel format used to create that context for later use. */
295@interface OverlayOpenGLContext: NSOpenGLContext
296{
297@private
298 NSOpenGLPixelFormat *m_pPixelFormat;
299 NSView *m_pView;
300}
301- (NSOpenGLPixelFormat*)openGLPixelFormat;
302@end
303
304@class DockOverlayView;
305
306/** The custom view class.
307 * This is the main class of the cocoa OpenGL implementation. It
308 * manages an frame buffer object for the rendering of the guest
309 * applications. The guest applications render in this frame buffer which
310 * is bind to an OpenGL texture. To display the guest content, an secondary
311 * shared OpenGL context of the main OpenGL context is created. The secondary
312 * context is marked as non opaque & the texture is displayed on an object
313 * which is composed out of the several visible region rectangles. */
314@interface OverlayView: NSView
315{
316@private
317 NSView *m_pParentView;
318 NSWindow *m_pOverlayWin;
319
320 NSOpenGLContext *m_pGLCtx;
321 NSOpenGLContext *m_pSharedGLCtx;
322 RTTHREAD mThread;
323
324 GLuint m_FBOId;
325
326 /** The corresponding dock tile view of this OpenGL view & all helper
327 * members. */
328 DockOverlayView *m_DockTileView;
329
330 GLfloat m_FBOThumbScaleX;
331 GLfloat m_FBOThumbScaleY;
332 uint64_t m_uiDockUpdateTime;
333
334 /* For clipping */
335 GLint m_cClipRects;
336 GLint *m_paClipRects;
337
338 /* Position/Size tracking */
339 NSPoint m_Pos;
340 NSSize m_Size;
341
342 /** This is necessary for clipping on the root window */
343 NSRect m_RootRect;
344 float m_yInvRootOffset;
345
346 CR_BLITTER *m_pBlitter;
347 WindowInfo *m_pWinInfo;
348 bool m_fNeedViewportUpdate;
349 bool m_fNeedCtxUpdate;
350 bool m_fDataVisible;
351 bool m_fEverSized;
352}
353- (id)initWithFrame:(NSRect)frame thread:(RTTHREAD)aThread parentView:(NSView*)pParentView winInfo:(WindowInfo*)pWinInfo;
354- (void)setGLCtx:(NSOpenGLContext*)pCtx;
355- (NSOpenGLContext*)glCtx;
356
357- (void)setParentView: (NSView*)view;
358- (NSView*)parentView;
359- (void)setOverlayWin: (NSWindow*)win;
360- (NSWindow*)overlayWin;
361
362- (void)setPos:(NSPoint)pos;
363- (NSPoint)pos;
364- (bool)isEverSized;
365- (void)setSize:(NSSize)size;
366- (NSSize)size;
367- (void)updateViewportCS;
368- (void)vboxReshapePerform;
369- (void)vboxReshapeOnResizePerform;
370- (void)vboxReshapeOnReparentPerform;
371
372- (void)createDockTile;
373- (void)deleteDockTile;
374
375- (void)makeCurrentFBO;
376- (void)swapFBO;
377- (void)vboxTryDraw;
378- (void)vboxTryDrawUI;
379- (void)vboxPresent:(const VBOXVR_SCR_COMPOSITOR*)pCompositor;
380- (void)vboxPresentCS:(const VBOXVR_SCR_COMPOSITOR*)pCompositor;
381- (void)vboxPresentToDockTileCS:(const VBOXVR_SCR_COMPOSITOR*)pCompositor;
382- (void)vboxPresentToViewCS:(const VBOXVR_SCR_COMPOSITOR*)pCompositor;
383- (void)presentComposition:(const VBOXVR_SCR_COMPOSITOR_ENTRY*)pChangedEntry;
384- (void)vboxBlitterSyncWindow;
385
386- (void)clearVisibleRegions;
387- (void)setVisibleRegions:(GLint)cRects paRects:(const GLint*)paRects;
388
389- (NSView*)dockTileScreen;
390- (void)reshapeDockTile;
391- (void)cleanupData;
392@end
393
394/** Helper view.
395 *
396 * This view is added as a sub view of the parent view to track
397 * main window changes. Whenever the main window is changed
398 * (which happens on fullscreen/seamless entry/exit) the overlay
399 * window is informed & can add them self as a child window
400 * again. */
401@class OverlayWindow;
402@interface OverlayHelperView: NSView
403{
404@private
405 OverlayWindow *m_pOverlayWindow;
406}
407-(id)initWithOverlayWindow:(OverlayWindow*)pOverlayWindow;
408@end
409
410/** Custom window class.
411 *
412 * This is the overlay window which contains our custom NSView.
413 * Its a direct child of the Qt Main window. It marks its background
414 * transparent & non opaque to make clipping possible. It also disable mouse
415 * events and handle frame change events of the parent view. */
416@interface OverlayWindow: NSWindow
417{
418@private
419 NSView *m_pParentView;
420 OverlayView *m_pOverlayView;
421 OverlayHelperView *m_pOverlayHelperView;
422 NSThread *m_Thread;
423}
424- (id)initWithParentView:(NSView*)pParentView overlayView:(OverlayView*)pOverlayView;
425- (void)parentWindowFrameChanged:(NSNotification *)note;
426- (void)parentWindowChanged:(NSWindow*)pWindow;
427@end
428
429@interface DockOverlayView: NSView
430{
431 NSBitmapImageRep *m_ThumbBitmap;
432 NSImage *m_ThumbImage;
433 NSLock *m_Lock;
434}
435- (void)dealloc;
436- (void)cleanup;
437- (void)lock;
438- (void)unlock;
439- (void)setFrame:(NSRect)frame;
440- (void)drawRect:(NSRect)aRect;
441- (NSBitmapImageRep*)thumbBitmap;
442- (NSImage*)thumbImage;
443@end
444
445@implementation DockOverlayView
446- (id)init
447{
448 self = [super init];
449
450 if (self)
451 {
452 /* We need a lock cause the thumb image could be accessed from the main
453 * thread when someone is calling display on the dock tile & from the
454 * OpenGL thread when the thumbnail is updated. */
455 m_Lock = [[NSLock alloc] init];
456 }
457
458 return self;
459}
460
461- (void)dealloc
462{
463 [self cleanup];
464 [m_Lock release];
465
466 [super dealloc];
467}
468
469- (void)cleanup
470{
471 if (m_ThumbImage != nil)
472 {
473 [m_ThumbImage release];
474 m_ThumbImage = nil;
475 }
476 if (m_ThumbBitmap != nil)
477 {
478 [m_ThumbBitmap release];
479 m_ThumbBitmap = nil;
480 }
481}
482
483- (void)lock
484{
485 [m_Lock lock];
486}
487
488- (void)unlock
489{
490 [m_Lock unlock];
491}
492
493- (void)setFrame:(NSRect)frame
494{
495 [super setFrame:frame];
496
497 [self lock];
498 [self cleanup];
499
500 if ( frame.size.width > 0
501 && frame.size.height > 0)
502 {
503 /* Create a buffer for our thumbnail image. Its in the size of this view. */
504 m_ThumbBitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
505 pixelsWide:frame.size.width
506 pixelsHigh:frame.size.height
507 bitsPerSample:8
508 samplesPerPixel:4
509 hasAlpha:YES
510 isPlanar:NO
511 colorSpaceName:NSDeviceRGBColorSpace
512 bitmapFormat:NSAlphaFirstBitmapFormat
513 bytesPerRow:frame.size.width * 4
514 bitsPerPixel:8 * 4];
515 m_ThumbImage = [[NSImage alloc] initWithSize:[m_ThumbBitmap size]];
516 [m_ThumbImage addRepresentation:m_ThumbBitmap];
517 }
518 [self unlock];
519}
520
521- (BOOL)isFlipped
522{
523 return YES;
524}
525
526- (void)drawRect:(NSRect)aRect
527{
528 NSRect frame;
529
530 [self lock];
531#ifdef SHOW_WINDOW_BACKGROUND
532 [[NSColor colorWithCalibratedRed:1.0 green:0.0 blue:0.0 alpha:0.7] set];
533 frame = [self frame];
534 [NSBezierPath fillRect:NSMakeRect(0, 0, frame.size.width, frame.size.height)];
535#endif /* SHOW_WINDOW_BACKGROUND */
536 if (m_ThumbImage != nil)
537 [m_ThumbImage drawAtPoint:NSMakePoint(0, 0) fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
538 [self unlock];
539}
540
541- (NSBitmapImageRep*)thumbBitmap
542{
543 return m_ThumbBitmap;
544}
545
546- (NSImage*)thumbImage
547{
548 return m_ThumbImage;
549}
550@end
551
552/********************************************************************************
553*
554* OverlayOpenGLContext class implementation
555*
556********************************************************************************/
557@implementation OverlayOpenGLContext
558
559-(id)initWithFormat:(NSOpenGLPixelFormat*)format shareContext:(NSOpenGLContext*)share
560{
561 m_pPixelFormat = NULL;
562 m_pView = NULL;
563
564 self = [super initWithFormat:format shareContext:share];
565 if (self)
566 m_pPixelFormat = format;
567
568 DEBUG_MSG(("OCTX(%p): init OverlayOpenGLContext\n", (void*)self));
569
570 return self;
571}
572
573- (void)dealloc
574{
575 DEBUG_MSG(("OCTX(%p): dealloc OverlayOpenGLContext\n", (void*)self));
576
577 [m_pPixelFormat release];
578
579 [super dealloc];
580}
581
582-(bool)isDoubleBuffer
583{
584 GLint val;
585 [m_pPixelFormat getValues:&val forAttribute:NSOpenGLPFADoubleBuffer forVirtualScreen:0];
586 return val == GL_TRUE ? YES : NO;
587}
588
589-(void)setView:(NSView*)view
590{
591 DEBUG_MSG(("OCTX(%p): setView: new view: %p\n", (void*)self, (void*)view));
592
593#if 1 /* def FBO */
594 m_pView = view;;
595#else
596 [super setView: view];
597#endif
598}
599
600-(NSView*)view
601{
602#if 1 /* def FBO */
603 return m_pView;
604#else
605 return [super view];
606#endif
607}
608
609-(void)clearDrawable
610{
611 DEBUG_MSG(("OCTX(%p): clearDrawable\n", (void*)self));
612
613 m_pView = NULL;;
614 [super clearDrawable];
615}
616
617-(NSOpenGLPixelFormat*)openGLPixelFormat
618{
619 return m_pPixelFormat;
620}
621
622@end
623
624/********************************************************************************
625*
626* OverlayHelperView class implementation
627*
628********************************************************************************/
629@implementation OverlayHelperView
630
631-(id)initWithOverlayWindow:(OverlayWindow*)pOverlayWindow
632{
633 self = [super initWithFrame:NSZeroRect];
634
635 m_pOverlayWindow = pOverlayWindow;
636
637 DEBUG_MSG(("OHVW(%p): init OverlayHelperView\n", (void*)self));
638
639 return self;
640}
641
642-(void)viewDidMoveToWindow
643{
644 DEBUG_MSG(("OHVW(%p): viewDidMoveToWindow: new win: %p\n", (void*)self, (void*)[self window]));
645
646 [m_pOverlayWindow parentWindowChanged:[self window]];
647}
648
649@end
650
651/********************************************************************************
652*
653* OverlayWindow class implementation
654*
655********************************************************************************/
656@implementation OverlayWindow
657
658- (id)initWithParentView:(NSView*)pParentView overlayView:(OverlayView*)pOverlayView
659{
660 NSWindow *pParentWin = nil;
661
662 if((self = [super initWithContentRect:NSZeroRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]))
663 {
664 m_pParentView = pParentView;
665 m_pOverlayView = pOverlayView;
666 m_Thread = [NSThread currentThread];
667
668 [m_pOverlayView setOverlayWin: self];
669
670 m_pOverlayHelperView = [[OverlayHelperView alloc] initWithOverlayWindow:self];
671 /* Add the helper view as a child of the parent view to get notifications */
672 [pParentView addSubview:m_pOverlayHelperView];
673
674 /* Make sure this window is transparent */
675#ifdef SHOW_WINDOW_BACKGROUND
676 /* For debugging */
677 [self setBackgroundColor:[NSColor colorWithCalibratedRed:1.0 green:0.0 blue:0.0 alpha:0.7]];
678#else
679 [self setBackgroundColor:[NSColor clearColor]];
680#endif
681 [self setOpaque:NO];
682 [self setAlphaValue:.999];
683 /* Disable mouse events for this window */
684 [self setIgnoresMouseEvents:YES];
685
686 pParentWin = [m_pParentView window];
687
688 /* Initial set the position to the parents view top/left (Compiz fix). */
689 [self setFrameOrigin:
690 [pParentWin convertBaseToScreen:
691 [m_pParentView convertPoint:NSZeroPoint toView:nil]]];
692
693 /* Set the overlay view as our content view */
694 [self setContentView:m_pOverlayView];
695
696 /* Add ourself as a child to the parent views window. Note: this has to
697 * be done last so that everything else is setup in
698 * parentWindowChanged. */
699 [pParentWin addChildWindow:self ordered:NSWindowAbove];
700 }
701 DEBUG_MSG(("OWIN(%p): init OverlayWindow\n", (void*)self));
702
703 return self;
704}
705
706- (void)dealloc
707{
708 DEBUG_MSG(("OWIN(%p): dealloc OverlayWindow\n", (void*)self));
709
710 [[NSNotificationCenter defaultCenter] removeObserver:self];
711
712 [m_pOverlayHelperView removeFromSuperview];
713 [m_pOverlayHelperView release];
714
715 [super dealloc];
716}
717
718- (void)parentWindowFrameChanged:(NSNotification*)pNote
719{
720 DEBUG_MSG(("OWIN(%p): parentWindowFrameChanged\n", (void*)self));
721
722 /* Reposition this window with the help of the OverlayView. Perform the
723 * call in the OpenGL thread. */
724 /*
725 [m_pOverlayView performSelector:@selector(vboxReshapePerform) onThread:m_Thread withObject:nil waitUntilDone:YES];
726 */
727
728 if ([m_pOverlayView isEverSized])
729 {
730 if([NSThread isMainThread])
731 [m_pOverlayView vboxReshapePerform];
732 else
733 [self performSelectorOnMainThread:@selector(vboxReshapePerform) withObject:nil waitUntilDone:NO];
734 }
735}
736
737- (void)parentWindowChanged:(NSWindow*)pWindow
738{
739 DEBUG_MSG(("OWIN(%p): parentWindowChanged\n", (void*)self));
740
741 [[NSNotificationCenter defaultCenter] removeObserver:self];
742
743 if(pWindow != nil)
744 {
745 /* Ask to get notifications when our parent window frame changes. */
746 [[NSNotificationCenter defaultCenter]
747 addObserver:self
748 selector:@selector(parentWindowFrameChanged:)
749 name:NSWindowDidResizeNotification
750 object:pWindow];
751 /* Add us self as child window */
752 [pWindow addChildWindow:self ordered:NSWindowAbove];
753 /* Reshape the overlay view after a short waiting time to let the main
754 * window resize itself properly. */
755 /*
756 [m_pOverlayView performSelector:@selector(vboxReshapePerform) withObject:nil afterDelay:0.2];
757 [NSTimer scheduledTimerWithTimeInterval:0.2 target:m_pOverlayView selector:@selector(vboxReshapePerform) userInfo:nil repeats:NO];
758 */
759
760 if ([m_pOverlayView isEverSized])
761 {
762 if([NSThread isMainThread])
763 [m_pOverlayView vboxReshapePerform];
764 else
765 [self performSelectorOnMainThread:@selector(vboxReshapePerform) withObject:nil waitUntilDone:NO];
766 }
767 }
768}
769
770@end
771
772/********************************************************************************
773*
774* OverlayView class implementation
775*
776********************************************************************************/
777@implementation OverlayView
778
779- (id)initWithFrame:(NSRect)frame thread:(RTTHREAD)aThread parentView:(NSView*)pParentView winInfo:(WindowInfo*)pWinInfo
780{
781 m_pParentView = pParentView;
782 /* Make some reasonable defaults */
783 m_pGLCtx = nil;
784 m_pSharedGLCtx = nil;
785 mThread = aThread;
786 m_FBOId = 0;
787 m_cClipRects = 0;
788 m_paClipRects = NULL;
789 m_Pos = NSZeroPoint;
790 m_Size = NSMakeSize(1, 1);
791 m_RootRect = NSMakeRect(0, 0, m_Size.width, m_Size.height);
792 m_yInvRootOffset = 0;
793 m_pBlitter = nil;
794 m_pWinInfo = pWinInfo;
795 m_fNeedViewportUpdate = true;
796 m_fNeedCtxUpdate = true;
797 m_fDataVisible = false;
798 m_fEverSized = false;
799
800 self = [super initWithFrame:frame];
801
802 DEBUG_MSG(("OVIW(%p): init OverlayView\n", (void*)self));
803
804 return self;
805}
806
807- (void)cleanupData
808{
809 [self deleteDockTile];
810
811 [self setGLCtx:nil];
812
813 if (m_pSharedGLCtx)
814 {
815 if ([m_pSharedGLCtx view] == self)
816 [m_pSharedGLCtx clearDrawable];
817
818 [m_pSharedGLCtx release];
819
820 m_pSharedGLCtx = nil;
821
822 CrBltTerm(m_pBlitter);
823
824 RTMemFree(m_pBlitter);
825
826 m_pBlitter = nil;
827 }
828
829 [self clearVisibleRegions];
830}
831
832- (void)dealloc
833{
834 DEBUG_MSG(("OVIW(%p): dealloc OverlayView\n", (void*)self));
835
836 [self cleanupData];
837
838 [super dealloc];
839}
840
841- (void)drawRect:(NSRect)aRect
842{
843 [self vboxTryDrawUI];
844}
845
846- (void)setGLCtx:(NSOpenGLContext*)pCtx
847{
848 DEBUG_MSG(("OVIW(%p): setGLCtx: new ctx: %p\n", (void*)self, (void*)pCtx));
849 if (m_pGLCtx == pCtx)
850 return;
851
852 /* ensure the context drawable is cleared to avoid holding a reference to inexistent view */
853 if (m_pGLCtx)
854 {
855 [m_pGLCtx clearDrawable];
856 [m_pGLCtx release];
857 /*[m_pGLCtx performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO];*/
858 }
859
860 m_pGLCtx = pCtx;
861 if (pCtx)
862 [pCtx retain];
863}
864
865- (NSOpenGLContext*)glCtx
866{
867 return m_pGLCtx;
868}
869
870- (NSView*)parentView
871{
872 return m_pParentView;
873}
874
875- (void)setParentView:(NSView*)pView
876{
877 DEBUG_MSG(("OVIW(%p): setParentView: new view: %p\n", (void*)self, (void*)pView));
878
879 m_pParentView = pView;
880}
881
882- (void)setOverlayWin:(NSWindow*)pWin
883{
884 DEBUG_MSG(("OVIW(%p): setOverlayWin: new win: %p\n", (void*)self, (void*)pWin));
885
886 m_pOverlayWin = pWin;
887}
888
889- (NSWindow*)overlayWin
890{
891 return m_pOverlayWin;
892}
893
894- (void)setPos:(NSPoint)pos
895{
896 DEBUG_MSG(("OVIW(%p): setPos: new pos: %d, %d\n", (void*)self, (int)pos.x, (int)pos.y));
897
898 m_Pos = pos;
899
900 if (m_fEverSized)
901 [self performSelectorOnMainThread:@selector(vboxReshapePerform) withObject:nil waitUntilDone:NO];
902
903 /* we need to redwar on regions change, however the compositor now is cleared
904 * because all compositor&window data-related modifications are performed with compositor cleared
905 * the renderspu client will re-set the compositor after modifications are complete
906 * this way we indicate renderspu generic code not to ignore the empty compositor */
907 /* generally this should not be needed for setPos because compositor should not be zeroed with it,
908 * in any way setting this flag here should not hurt as it will be re-set on next present */
909 m_pWinInfo->fCompositorPresentEmpty = GL_TRUE;
910}
911
912- (NSPoint)pos
913{
914 return m_Pos;
915}
916
917- (bool)isEverSized
918{
919 return m_fEverSized;
920}
921
922- (void)setSize:(NSSize)size
923{
924 NSOpenGLContext *pCurCtx;
925 NSView *pCurView;
926 m_Size = size;
927
928 m_fEverSized = true;
929
930 DEBUG_MSG(("OVIW(%p): setSize: new size: %dx%d\n", (void*)self, (int)size.width, (int)size.height));
931 [self performSelectorOnMainThread:@selector(vboxReshapeOnResizePerform) withObject:nil waitUntilDone:NO];
932
933 /* we need to redwar on regions change, however the compositor now is cleared
934 * because all compositor&window data-related modifications are performed with compositor cleared
935 * the renderspu client will re-set the compositor after modifications are complete
936 * this way we indicate renderspu generic code not to ignore the empty compositor */
937 /* generally this should not be needed for setSize because compositor should not be zeroed with it,
938 * in any way setting this flag here should not hurt as it will be re-set on next present */
939 m_pWinInfo->fCompositorPresentEmpty = GL_TRUE;
940}
941
942- (NSSize)size
943{
944 return m_Size;
945}
946
947- (void)updateViewportCS
948{
949 DEBUG_MSG(("OVIW(%p): updateViewport\n", (void*)self));
950
951 /* Update the viewport for our OpenGL view */
952 [m_pSharedGLCtx update];
953
954 [self vboxBlitterSyncWindow];
955
956 /* Clear background to transparent */
957 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
958}
959
960- (void)vboxReshapeOnResizePerform
961{
962 [self vboxReshapePerform];
963
964 [self createDockTile];
965 /* have to rebind GL_TEXTURE_RECTANGLE_ARB as m_FBOTexId could be changed in updateFBO call */
966 m_fNeedViewportUpdate = true;
967#if 0
968 pCurCtx = [NSOpenGLContext currentContext];
969 if (pCurCtx && pCurCtx == m_pGLCtx && (pCurView = [pCurCtx view]) == self)
970 {
971 [m_pGLCtx update];
972 m_fNeedCtxUpdate = false;
973 }
974 else
975 {
976 /* do it in a lazy way */
977 m_fNeedCtxUpdate = true;
978 }
979#endif
980}
981
982- (void)vboxReshapeOnReparentPerform
983{
984 [self createDockTile];
985}
986
987- (void)vboxReshapePerform
988{
989 NSRect parentFrame = NSZeroRect;
990 NSPoint parentPos = NSZeroPoint;
991 NSPoint childPos = NSZeroPoint;
992 NSRect childFrame = NSZeroRect;
993 NSRect newFrame = NSZeroRect;
994
995 DEBUG_MSG(("OVIW(%p): vboxReshapePerform\n", (void*)self));
996
997 parentFrame = [m_pParentView frame];
998 DEBUG_MSG(("FIXED parentFrame [%f:%f], [%f:%f]\n", parentFrame.origin.x, parentFrame.origin.y, parentFrame.size.width, parentFrame.size.height));
999 parentPos = parentFrame.origin;
1000 parentPos.y += parentFrame.size.height;
1001 DEBUG_MSG(("FIXED(view) parentPos [%f:%f]\n", parentPos.x, parentPos.y));
1002 parentPos = [m_pParentView convertPoint:parentPos toView:nil];
1003 DEBUG_MSG(("FIXED parentPos(win) [%f:%f]\n", parentPos.x, parentPos.y));
1004 parentPos = [[m_pParentView window] convertBaseToScreen:parentPos];
1005 DEBUG_MSG(("FIXED parentPos(screen) [%f:%f]\n", parentPos.x, parentPos.y));
1006 parentFrame.origin = parentPos;
1007
1008 childPos = NSMakePoint(m_Pos.x, m_Pos.y + m_Size.height);
1009 DEBUG_MSG(("FIXED(view) childPos [%f:%f]\n", childPos.x, childPos.y));
1010 childPos = [m_pParentView convertPoint:childPos toView:nil];
1011 DEBUG_MSG(("FIXED(win) childPos [%f:%f]\n", childPos.x, childPos.y));
1012 childPos = [[m_pParentView window] convertBaseToScreen:childPos];
1013 DEBUG_MSG(("FIXED childPos(screen) [%f:%f]\n", childPos.x, childPos.y));
1014 childFrame = NSMakeRect(childPos.x, childPos.y, m_Size.width, m_Size.height);
1015 DEBUG_MSG(("FIXED childFrame [%f:%f], [%f:%f]\n", childFrame.origin.x, childFrame.origin.y, childFrame.size.width, childFrame.size.height));
1016
1017 /* We have to make sure that the overlay window will not be displayed out
1018 * of the parent window. So intersect both frames & use the result as the new
1019 * frame for the window. */
1020 newFrame = NSIntersectionRect(parentFrame, childFrame);
1021
1022 DEBUG_MSG(("[%#p]: parentFrame pos[%f : %f] size[%f : %f]\n",
1023 (void*)self,
1024 parentFrame.origin.x, parentFrame.origin.y,
1025 parentFrame.size.width, parentFrame.size.height));
1026 DEBUG_MSG(("[%#p]: childFrame pos[%f : %f] size[%f : %f]\n",
1027 (void*)self,
1028 childFrame.origin.x, childFrame.origin.y,
1029 childFrame.size.width, childFrame.size.height));
1030
1031 DEBUG_MSG(("[%#p]: newFrame pos[%f : %f] size[%f : %f]\n",
1032 (void*)self,
1033 newFrame.origin.x, newFrame.origin.y,
1034 newFrame.size.width, newFrame.size.height));
1035
1036 /* Later we have to correct the texture position in the case the window is
1037 * out of the parents window frame. So save the shift values for later use. */
1038 m_RootRect.origin.x = newFrame.origin.x - childFrame.origin.x;
1039 m_RootRect.origin.y = childFrame.size.height + childFrame.origin.y - (newFrame.size.height + newFrame.origin.y);
1040 m_RootRect.size = newFrame.size;
1041 m_yInvRootOffset = newFrame.origin.y - childFrame.origin.y;
1042
1043 DEBUG_MSG(("[%#p]: m_RootRect pos[%f : %f] size[%f : %f]\n",
1044 (void*)self,
1045 m_RootRect.origin.x, m_RootRect.origin.y,
1046 m_RootRect.size.width, m_RootRect.size.height));
1047
1048
1049 /*
1050 NSScrollView *pScrollView = [[[m_pParentView window] contentView] enclosingScrollView];
1051 if (pScrollView)
1052 {
1053 NSRect scrollRect = [pScrollView documentVisibleRect];
1054 NSRect scrollRect = [m_pParentView visibleRect];
1055 printf ("sc rect: %d %d %d %d\n", (int) scrollRect.origin.x,(int) scrollRect.origin.y,(int) scrollRect.size.width,(int) scrollRect.size.height);
1056 NSRect b = [[m_pParentView superview] bounds];
1057 printf ("bound rect: %d %d %d %d\n", (int) b.origin.x,(int) b.origin.y,(int) b.size.width,(int) b.size.height);
1058 newFrame.origin.x += scrollRect.origin.x;
1059 newFrame.origin.y += scrollRect.origin.y;
1060 }
1061 */
1062
1063 /* Set the new frame. */
1064 [[self window] setFrame:newFrame display:YES];
1065
1066 /* Inform the dock tile view as well */
1067 [self reshapeDockTile];
1068
1069 /* Make sure the context is updated according */
1070 /* [self updateViewport]; */
1071 if (m_pSharedGLCtx)
1072 {
1073 VBOX_CR_RENDER_CTX_INFO CtxInfo;
1074 vboxCtxEnter(m_pSharedGLCtx, &CtxInfo);
1075
1076 [self updateViewportCS];
1077
1078 vboxCtxLeave(&CtxInfo);
1079 }
1080}
1081
1082- (void)createDockTile
1083{
1084 NSView *pDockScreen = nil;
1085 [self deleteDockTile];
1086
1087 /* Is there a dock tile preview enabled in the GUI? If so setup a
1088 * additional thumbnail view for the dock tile. */
1089 pDockScreen = [self dockTileScreen];
1090 if (pDockScreen)
1091 {
1092 m_DockTileView = [[DockOverlayView alloc] init];
1093 [self reshapeDockTile];
1094 [pDockScreen addSubview:m_DockTileView];
1095 }
1096}
1097
1098- (void)deleteDockTile
1099{
1100 if (m_DockTileView != nil)
1101 {
1102 [m_DockTileView removeFromSuperview];
1103 [m_DockTileView release];
1104 m_DockTileView = nil;
1105 }
1106}
1107
1108- (void)makeCurrentFBO
1109{
1110 DEBUG_MSG(("OVIW(%p): makeCurrentFBO\n", (void*)self));
1111
1112 if (m_pGLCtx)
1113 {
1114 if ([m_pGLCtx view] != self)
1115 {
1116 /* We change the active view, so flush first */
1117 if([NSOpenGLContext currentContext] != 0)
1118 glFlush();
1119 [m_pGLCtx setView: self];
1120 CHECK_GL_ERROR();
1121 }
1122 /*
1123 if ([NSOpenGLContext currentContext] != m_pGLCtx)
1124 */
1125 {
1126 [m_pGLCtx makeCurrentContext];
1127 CHECK_GL_ERROR();
1128 if (m_fNeedCtxUpdate == true)
1129 {
1130 [m_pGLCtx update];
1131 m_fNeedCtxUpdate = false;
1132 }
1133 }
1134
1135 if (!m_FBOId)
1136 {
1137 glGenFramebuffersEXT(1, &m_FBOId);
1138 Assert(m_FBOId);
1139 }
1140
1141 }
1142}
1143
1144- (bool)vboxSharedCtxCreate
1145{
1146 if (m_pSharedGLCtx)
1147 return true;
1148
1149 Assert(!m_pBlitter);
1150 m_pBlitter = RTMemAlloc(sizeof (*m_pBlitter));
1151 if (!m_pBlitter)
1152 {
1153 DEBUG_WARN(("m_pBlitter allocation failed"));
1154 return false;
1155 }
1156
1157 int rc = CrBltInit(m_pBlitter, NULL, false, false, &render_spu.GlobalShaders, &render_spu.blitterDispatch);
1158 if (RT_SUCCESS(rc))
1159 {
1160 DEBUG_MSG(("blitter created successfully for view 0x%p\n", (void*)self));
1161 }
1162 else
1163 {
1164 DEBUG_WARN(("CrBltInit failed, rc %d", rc));
1165 RTMemFree(m_pBlitter);
1166 m_pBlitter = NULL;
1167 return false;
1168 }
1169
1170 GLint opaque = 0;
1171 /* Create a shared context out of the main context. Use the same pixel format. */
1172 NSOpenGLContext *pSharedGLCtx = [[NSOpenGLContext alloc] initWithFormat:[(OverlayOpenGLContext*)m_pGLCtx openGLPixelFormat] shareContext:m_pGLCtx];
1173
1174 /* Set the new context as non opaque */
1175 [pSharedGLCtx setValues:&opaque forParameter:NSOpenGLCPSurfaceOpacity];
1176 /* Set this view as the drawable for the new context */
1177 [pSharedGLCtx setView: self];
1178 m_fNeedViewportUpdate = true;
1179
1180 m_pSharedGLCtx = pSharedGLCtx;
1181
1182 return true;
1183}
1184
1185- (void)vboxTryDraw
1186{
1187 glFlush();
1188
1189 /* issue to the gui thread */
1190 [self setNeedsDisplay:YES];
1191}
1192
1193- (void)vboxTryDrawUI
1194{
1195 const VBOXVR_SCR_COMPOSITOR *pCompositor = renderspuVBoxCompositorAcquire(m_pWinInfo);
1196 if (!m_fDataVisible && !pCompositor)
1197 return;
1198
1199 VBOXVR_SCR_COMPOSITOR TmpCompositor;
1200
1201 if (pCompositor)
1202 {
1203 if (!m_pSharedGLCtx)
1204 {
1205 Assert(!m_fDataVisible);
1206 renderspuVBoxCompositorRelease(m_pWinInfo);
1207 if (![self vboxSharedCtxCreate])
1208 {
1209 DEBUG_WARN(("vboxSharedCtxCreate failed\n"));
1210 return;
1211 }
1212
1213 Assert(m_pSharedGLCtx);
1214
1215 pCompositor = renderspuVBoxCompositorAcquire(m_pWinInfo);
1216 Assert(!m_fDataVisible);
1217 if (!pCompositor)
1218 return;
1219 }
1220 }
1221 else
1222 {
1223 CrVrScrCompositorInit(&TmpCompositor, NULL);
1224 pCompositor = &TmpCompositor;
1225 }
1226
1227 if ([self lockFocusIfCanDraw])
1228 {
1229 [self vboxPresent:pCompositor];
1230 if (pCompositor != &TmpCompositor)
1231 renderspuVBoxCompositorRelease(m_pWinInfo);
1232
1233 [self unlockFocus];
1234 }
1235 else
1236 {
1237 [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(vboxTryDrawUI) userInfo:nil repeats:NO];
1238 }
1239}
1240
1241- (void)swapFBO
1242{
1243 [m_pGLCtx flushBuffer];
1244}
1245
1246- (void)vboxPresent:(const VBOXVR_SCR_COMPOSITOR*)pCompositor
1247{
1248 VBOX_CR_RENDER_CTX_INFO CtxInfo;
1249
1250 DEBUG_MSG(("OVIW(%p): renderFBOToView\n", (void*)self));
1251
1252 Assert(pCompositor);
1253
1254 vboxCtxEnter(m_pSharedGLCtx, &CtxInfo);
1255
1256 [self vboxPresentCS:pCompositor];
1257
1258 vboxCtxLeave(&CtxInfo);
1259}
1260
1261- (void)vboxPresentCS:(const VBOXVR_SCR_COMPOSITOR*)pCompositor
1262{
1263 {
1264 if ([m_pSharedGLCtx view] != self)
1265 {
1266 DEBUG_MSG(("OVIW(%p): not current view of shared ctx! Switching ...\n", (void*)self));
1267 [m_pSharedGLCtx setView: self];
1268 m_fNeedViewportUpdate = true;
1269 }
1270
1271 if (m_fNeedViewportUpdate)
1272 {
1273 [self updateViewportCS];
1274 m_fNeedViewportUpdate = false;
1275 }
1276
1277 /* Render FBO content to the dock tile when necessary. */
1278 [self vboxPresentToDockTileCS:pCompositor];
1279 /* change to #if 0 to see thumbnail image */
1280#if 1
1281 [self vboxPresentToViewCS:pCompositor];
1282#else
1283 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1284 [m_pSharedGLCtx flushBuffer];
1285#endif
1286
1287 }
1288}
1289
1290DECLINLINE(void) vboxNSRectToRect(const NSRect *pR, RTRECT *pRect)
1291{
1292 pRect->xLeft = (int)pR->origin.x;
1293 pRect->yTop = (int)pR->origin.y;
1294 pRect->xRight = (int)(pR->origin.x + pR->size.width);
1295 pRect->yBottom = (int)(pR->origin.y + pR->size.height);
1296}
1297
1298DECLINLINE(void) vboxNSRectToRectUnstretched(const NSRect *pR, RTRECT *pRect, float xStretch, float yStretch)
1299{
1300 pRect->xLeft = (int)(pR->origin.x / xStretch);
1301 pRect->yTop = (int)(pR->origin.y / yStretch);
1302 pRect->xRight = (int)((pR->origin.x + pR->size.width) / xStretch);
1303 pRect->yBottom = (int)((pR->origin.y + pR->size.height) / yStretch);
1304}
1305
1306DECLINLINE(void) vboxNSRectToRectStretched(const NSRect *pR, RTRECT *pRect, float xStretch, float yStretch)
1307{
1308 pRect->xLeft = (int)(pR->origin.x * xStretch);
1309 pRect->yTop = (int)(pR->origin.y * yStretch);
1310 pRect->xRight = (int)((pR->origin.x + pR->size.width) * xStretch);
1311 pRect->yBottom = (int)((pR->origin.y + pR->size.height) * yStretch);
1312}
1313
1314- (void)vboxPresentToViewCS:(const VBOXVR_SCR_COMPOSITOR*)pCompositor
1315{
1316 NSRect r = [self frame];
1317 float xStretch, yStretch;
1318 DEBUG_MSG(("OVIW(%p): rF2V frame: [%i, %i, %i, %i]\n", (void*)self, (int)r.origin.x, (int)r.origin.y, (int)r.size.width, (int)r.size.height));
1319
1320#if 1 /* Set to 0 to see the docktile instead of the real output */
1321 VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR CIter;
1322 const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry;
1323
1324 CrVrScrCompositorConstIterInit(pCompositor, &CIter);
1325
1326 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
1327 glDrawBuffer(GL_BACK);
1328
1329 /* Clear background to transparent */
1330 glClear(GL_COLOR_BUFFER_BIT);
1331
1332 m_fDataVisible = false;
1333
1334 CrVrScrCompositorGetStretching(pCompositor, &xStretch, &yStretch);
1335
1336 while ((pEntry = CrVrScrCompositorConstIterNext(&CIter)) != NULL)
1337 {
1338 uint32_t cRegions;
1339 const RTRECT *paSrcRegions, *paDstRegions;
1340 int rc = CrVrScrCompositorEntryRegionsGet(pCompositor, pEntry, &cRegions, &paSrcRegions, &paDstRegions, NULL);
1341 uint32_t fFlags = CrVrScrCompositorEntryFlagsCombinedGet(pCompositor, pEntry);
1342 if (RT_SUCCESS(rc))
1343 {
1344 uint32_t i;
1345 int rc = CrBltEnter(m_pBlitter);
1346 if (RT_SUCCESS(rc))
1347 {
1348 for (i = 0; i < cRegions; ++i)
1349 {
1350 const RTRECT * pSrcRect = &paSrcRegions[i];
1351 const RTRECT * pDstRect = &paDstRegions[i];
1352 RTRECT DstRect, RestrictDstRect;
1353 RTRECT SrcRect, RestrictSrcRect;
1354
1355 vboxNSRectToRect(&m_RootRect, &RestrictDstRect);
1356 VBoxRectIntersected(&RestrictDstRect, pDstRect, &DstRect);
1357
1358 if (VBoxRectIsZero(&DstRect))
1359 continue;
1360
1361 VBoxRectTranslate(&DstRect, -RestrictDstRect.xLeft, -RestrictDstRect.yTop);
1362
1363 vboxNSRectToRectUnstretched(&m_RootRect, &RestrictSrcRect, xStretch, yStretch);
1364 VBoxRectTranslate(&RestrictSrcRect, -CrVrScrCompositorEntryRectGet(pEntry)->xLeft, -CrVrScrCompositorEntryRectGet(pEntry)->yTop);
1365 VBoxRectIntersected(&RestrictSrcRect, pSrcRect, &SrcRect);
1366
1367 if (VBoxRectIsZero(&SrcRect))
1368 continue;
1369
1370 pSrcRect = &SrcRect;
1371 pDstRect = &DstRect;
1372
1373 const CR_TEXDATA *pTexData = CrVrScrCompositorEntryTexGet(pEntry);
1374
1375 CrBltBlitTexMural(m_pBlitter, true, CrTdTexGet(pTexData), pSrcRect, pDstRect, 1, fFlags | CRBLT_F_NOALPHA);
1376
1377 m_fDataVisible = true;
1378 }
1379 CrBltLeave(m_pBlitter);
1380 }
1381 else
1382 {
1383 DEBUG_WARN(("CrBltEnter failed rc %d", rc));
1384 }
1385 }
1386 else
1387 {
1388 Assert(0);
1389 DEBUG_MSG_1(("BlitStretched: CrVrScrCompositorEntryRegionsGet failed rc %d\n", rc));
1390 }
1391 }
1392#endif
1393 /*
1394 glFinish();
1395 */
1396 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1397 [m_pSharedGLCtx flushBuffer];
1398}
1399
1400- (void)presentComposition:(const VBOXVR_SCR_COMPOSITOR_ENTRY*)pChangedEntry
1401{
1402 [self vboxTryDraw];
1403}
1404
1405- (void)vboxBlitterSyncWindow
1406{
1407 CR_BLITTER_WINDOW WinInfo;
1408 NSRect r;
1409
1410 if (!m_pBlitter)
1411 return;
1412
1413 memset(&WinInfo, 0, sizeof (WinInfo));
1414
1415 r = [self frame];
1416 WinInfo.width = r.size.width;
1417 WinInfo.height = r.size.height;
1418
1419 Assert(WinInfo.width == m_RootRect.size.width);
1420 Assert(WinInfo.height == m_RootRect.size.height);
1421
1422 /*CrBltMuralSetCurrentInfo(m_pBlitter, NULL);*/
1423
1424 CrBltMuralSetCurrentInfo(m_pBlitter, &WinInfo);
1425 CrBltCheckUpdateViewport(m_pBlitter);
1426}
1427
1428#ifdef VBOX_WITH_CRDUMPER_THUMBNAIL
1429static int g_cVBoxTgaCtr = 0;
1430#endif
1431- (void)vboxPresentToDockTileCS:(const VBOXVR_SCR_COMPOSITOR*)pCompositor
1432{
1433 NSRect r = [self frame];
1434 NSRect rr = NSZeroRect;
1435 GLint i = 0;
1436 NSDockTile *pDT = nil;
1437 float xStretch, yStretch;
1438
1439 if ([m_DockTileView thumbBitmap] != nil)
1440 {
1441 /* Only update after at least 200 ms, cause glReadPixels is
1442 * heavy performance wise. */
1443 uint64_t uiNewTime = RTTimeMilliTS();
1444 VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR CIter;
1445 const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry;
1446
1447 if (uiNewTime - m_uiDockUpdateTime > 200)
1448 {
1449 m_uiDockUpdateTime = uiNewTime;
1450#if 0
1451 /* todo: check this for optimization */
1452 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, myTextureName);
1453 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_STORAGE_HINT_APPLE,
1454 GL_STORAGE_SHARED_APPLE);
1455 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1456 glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA,
1457 sizex, sizey, 0, GL_BGRA,
1458 GL_UNSIGNED_INT_8_8_8_8_REV, myImagePtr);
1459 glCopyTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB,
1460 0, 0, 0, 0, 0, image_width, image_height);
1461 glFlush();
1462 /* Do other work processing here, using a double or triple buffer */
1463 glGetTexImage(GL_TEXTURE_RECTANGLE_ARB, 0, GL_BGRA,
1464 GL_UNSIGNED_INT_8_8_8_8_REV, pixels);
1465#endif
1466 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
1467 glDrawBuffer(GL_BACK);
1468
1469 /* Clear background to transparent */
1470 glClear(GL_COLOR_BUFFER_BIT);
1471
1472 rr = [m_DockTileView frame];
1473
1474 CrVrScrCompositorGetStretching(pCompositor, &xStretch, &yStretch);
1475
1476 CrVrScrCompositorConstIterInit(pCompositor, &CIter);
1477 while ((pEntry = CrVrScrCompositorConstIterNext(&CIter)) != NULL)
1478 {
1479 uint32_t cRegions;
1480 const RTRECT *paSrcRegions, *paDstRegions;
1481 int rc = CrVrScrCompositorEntryRegionsGet(pCompositor, pEntry, &cRegions, &paSrcRegions, &paDstRegions, NULL);
1482 uint32_t fFlags = CrVrScrCompositorEntryFlagsCombinedGet(pCompositor, pEntry);
1483 if (RT_SUCCESS(rc))
1484 {
1485 uint32_t i;
1486 int rc = CrBltEnter(m_pBlitter);
1487 if (RT_SUCCESS(rc))
1488 {
1489 for (i = 0; i < cRegions; ++i)
1490 {
1491 const RTRECT * pSrcRect = &paSrcRegions[i];
1492 const RTRECT * pDstRect = &paDstRegions[i];
1493 RTRECT SrcRect, DstRect, RestrictSrcRect, RestrictDstRect;
1494
1495 vboxNSRectToRect(&m_RootRect, &RestrictDstRect);
1496 VBoxRectIntersected(&RestrictDstRect, pDstRect, &DstRect);
1497
1498 VBoxRectTranslate(&DstRect, -RestrictDstRect.xLeft, -RestrictDstRect.yTop);
1499
1500 VBoxRectScale(&DstRect, m_FBOThumbScaleX, m_FBOThumbScaleY);
1501
1502 if (VBoxRectIsZero(&DstRect))
1503 continue;
1504
1505 vboxNSRectToRectUnstretched(&m_RootRect, &RestrictSrcRect, xStretch, yStretch);
1506 VBoxRectTranslate(&RestrictSrcRect, -CrVrScrCompositorEntryRectGet(pEntry)->xLeft, -CrVrScrCompositorEntryRectGet(pEntry)->yTop);
1507 VBoxRectIntersected(&RestrictSrcRect, pSrcRect, &SrcRect);
1508
1509 if (VBoxRectIsZero(&SrcRect))
1510 continue;
1511
1512 pSrcRect = &SrcRect;
1513 pDstRect = &DstRect;
1514
1515 const CR_TEXDATA *pTexData = CrVrScrCompositorEntryTexGet(pEntry);
1516
1517 CrBltBlitTexMural(m_pBlitter, true, CrTdTexGet(pTexData), pSrcRect, pDstRect, 1, fFlags);
1518 }
1519 CrBltLeave(m_pBlitter);
1520 }
1521 else
1522 {
1523 DEBUG_WARN(("CrBltEnter failed rc %d", rc));
1524 }
1525 }
1526 else
1527 {
1528 Assert(0);
1529 DEBUG_MSG_1(("BlitStretched: CrVrScrCompositorEntryRegionsGet failed rc %d\n", rc));
1530 }
1531 }
1532
1533 glFinish();
1534
1535 glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
1536 glReadBuffer(GL_BACK);
1537 /* Here the magic of reading the FBO content in our own buffer
1538 * happens. We have to lock this access, in the case the dock
1539 * is updated currently. */
1540 [m_DockTileView lock];
1541 glReadPixels(0, m_RootRect.size.height - rr.size.height, rr.size.width, rr.size.height,
1542 GL_BGRA,
1543 GL_UNSIGNED_INT_8_8_8_8,
1544 [[m_DockTileView thumbBitmap] bitmapData]);
1545 [m_DockTileView unlock];
1546
1547#ifdef VBOX_WITH_CRDUMPER_THUMBNAIL
1548 ++g_cVBoxTgaCtr;
1549 crDumpNamedTGAF((GLint)rr.size.width, (GLint)rr.size.height,
1550 [[m_DockTileView thumbBitmap] bitmapData], "/Users/leo/vboxdumps/dump%d.tga", g_cVBoxTgaCtr);
1551#endif
1552
1553 pDT = [[NSApplication sharedApplication] dockTile];
1554
1555 /* Send a display message to the dock tile in the main thread */
1556 [[[NSApplication sharedApplication] dockTile] performSelectorOnMainThread:@selector(display) withObject:nil waitUntilDone:NO];
1557 }
1558 }
1559}
1560
1561- (void)clearVisibleRegions
1562{
1563 if(m_paClipRects)
1564 {
1565 RTMemFree(m_paClipRects);
1566 m_paClipRects = NULL;
1567 }
1568 m_cClipRects = 0;
1569}
1570
1571- (void)setVisibleRegions:(GLint)cRects paRects:(const GLint*)paRects
1572{
1573 GLint cOldRects = m_cClipRects;
1574
1575 DEBUG_MSG_1(("OVIW(%p): setVisibleRegions: cRects=%d\n", (void*)self, cRects));
1576
1577 [self clearVisibleRegions];
1578
1579 if (cRects > 0)
1580 {
1581#ifdef DEBUG_poetzsch
1582 int i =0;
1583 for (i = 0; i < cRects; ++i)
1584 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]));
1585#endif
1586
1587 m_paClipRects = (GLint*)RTMemAlloc(sizeof(GLint) * 4 * cRects);
1588 m_cClipRects = cRects;
1589 memcpy(m_paClipRects, paRects, sizeof(GLint) * 4 * cRects);
1590 }
1591
1592 /* we need to redwar on regions change, however the compositor now is cleared
1593 * because all compositor&window data-related modifications are performed with compositor cleared
1594 * the renderspu client will re-set the compositor after modifications are complete
1595 * this way we indicate renderspu generic code not to ignore the empty compositor */
1596 m_pWinInfo->fCompositorPresentEmpty = GL_TRUE;
1597}
1598
1599- (NSView*)dockTileScreen
1600{
1601 NSView *contentView = [[[NSApplication sharedApplication] dockTile] contentView];
1602 NSView *screenContent = nil;
1603 /* First try the new variant which checks if this window is within the
1604 screen which is previewed in the dock. */
1605 if ([contentView respondsToSelector:@selector(screenContentWithParentView:)])
1606 screenContent = [contentView performSelector:@selector(screenContentWithParentView:) withObject:(id)m_pParentView];
1607 /* If it fails, fall back to the old variant (VBox...) */
1608 else if ([contentView respondsToSelector:@selector(screenContent)])
1609 screenContent = [contentView performSelector:@selector(screenContent)];
1610 return screenContent;
1611}
1612
1613- (void)reshapeDockTile
1614{
1615 NSRect newFrame = NSZeroRect;
1616
1617 NSView *pView = [self dockTileScreen];
1618 if (pView != nil)
1619 {
1620 NSRect dockFrame = [pView frame];
1621 /* todo: this is not correct, we should use framebuffer size here, while parent view frame size may differ in case of scrolling */
1622 NSRect parentFrame = [m_pParentView frame];
1623
1624 m_FBOThumbScaleX = (float)dockFrame.size.width / parentFrame.size.width;
1625 m_FBOThumbScaleY = (float)dockFrame.size.height / parentFrame.size.height;
1626 newFrame = NSMakeRect((int)(m_Pos.x * m_FBOThumbScaleX), (int)(dockFrame.size.height - (m_Pos.y + m_Size.height - m_yInvRootOffset) * m_FBOThumbScaleY), (int)(m_Size.width * m_FBOThumbScaleX), (int)(m_Size.height * m_FBOThumbScaleY));
1627 /*
1628 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));
1629 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));
1630 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);
1631 */
1632 [m_DockTileView setFrame: newFrame];
1633 }
1634}
1635
1636@end
1637
1638/********************************************************************************
1639*
1640* OpenGL context management
1641*
1642********************************************************************************/
1643void cocoaGLCtxCreate(NativeNSOpenGLContextRef *ppCtx, GLbitfield fVisParams, NativeNSOpenGLContextRef pSharedCtx)
1644{
1645 NSOpenGLPixelFormat *pFmt = nil;
1646
1647 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1648
1649 NSOpenGLPixelFormatAttribute attribs[24] =
1650 {
1651 NSOpenGLPFAWindow,
1652 NSOpenGLPFAAccelerated,
1653 NSOpenGLPFAColorSize, (NSOpenGLPixelFormatAttribute)24
1654 };
1655
1656 int i = 4;
1657
1658 if (fVisParams & CR_ALPHA_BIT)
1659 {
1660 DEBUG_MSG(("CR_ALPHA_BIT requested\n"));
1661 attribs[i++] = NSOpenGLPFAAlphaSize;
1662 attribs[i++] = 8;
1663 }
1664 if (fVisParams & CR_DEPTH_BIT)
1665 {
1666 DEBUG_MSG(("CR_DEPTH_BIT requested\n"));
1667 attribs[i++] = NSOpenGLPFADepthSize;
1668 attribs[i++] = 24;
1669 }
1670 if (fVisParams & CR_STENCIL_BIT)
1671 {
1672 DEBUG_MSG(("CR_STENCIL_BIT requested\n"));
1673 attribs[i++] = NSOpenGLPFAStencilSize;
1674 attribs[i++] = 8;
1675 }
1676 if (fVisParams & CR_ACCUM_BIT)
1677 {
1678 DEBUG_MSG(("CR_ACCUM_BIT requested\n"));
1679 attribs[i++] = NSOpenGLPFAAccumSize;
1680 if (fVisParams & CR_ALPHA_BIT)
1681 attribs[i++] = 32;
1682 else
1683 attribs[i++] = 24;
1684 }
1685 if (fVisParams & CR_MULTISAMPLE_BIT)
1686 {
1687 DEBUG_MSG(("CR_MULTISAMPLE_BIT requested\n"));
1688 attribs[i++] = NSOpenGLPFASampleBuffers;
1689 attribs[i++] = 1;
1690 attribs[i++] = NSOpenGLPFASamples;
1691 attribs[i++] = 4;
1692 }
1693 if (fVisParams & CR_DOUBLE_BIT)
1694 {
1695 DEBUG_MSG(("CR_DOUBLE_BIT requested\n"));
1696 attribs[i++] = NSOpenGLPFADoubleBuffer;
1697 }
1698 if (fVisParams & CR_STEREO_BIT)
1699 {
1700 /* We don't support that.
1701 DEBUG_MSG(("CR_STEREO_BIT requested\n"));
1702 attribs[i++] = NSOpenGLPFAStereo;
1703 */
1704 }
1705
1706 /* Mark the end */
1707 attribs[i++] = 0;
1708
1709 /* Choose a pixel format */
1710 pFmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
1711
1712 if (pFmt)
1713 {
1714 *ppCtx = [[OverlayOpenGLContext alloc] initWithFormat:pFmt shareContext:pSharedCtx];
1715
1716 /* Enable multi threaded OpenGL engine */
1717 /*
1718 CGLContextObj cglCtx = [*ppCtx CGLContextObj];
1719 CGLError err = CGLEnable(cglCtx, kCGLCEMPEngine);
1720 if (err != kCGLNoError)
1721 printf ("Couldn't enable MT OpenGL engine!\n");
1722 */
1723
1724 DEBUG_MSG(("New context %X\n", (uint)*ppCtx));
1725 }
1726
1727 [pPool release];
1728}
1729
1730void cocoaGLCtxDestroy(NativeNSOpenGLContextRef pCtx)
1731{
1732 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1733
1734 [pCtx release];
1735 /*[pCtx performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO];*/
1736
1737 [pPool release];
1738}
1739
1740/********************************************************************************
1741*
1742* View management
1743*
1744********************************************************************************/
1745void cocoaViewCreate(NativeNSViewRef *ppView, WindowInfo *pWinInfo, NativeNSViewRef pParentView, GLbitfield fVisParams)
1746{
1747 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1748
1749 /* Create our worker view */
1750 OverlayView* pView = [[OverlayView alloc] initWithFrame:NSZeroRect thread:RTThreadSelf() parentView:pParentView winInfo:pWinInfo];
1751
1752 if (pView)
1753 {
1754 /* We need a real window as container for the view */
1755 [[OverlayWindow alloc] initWithParentView:pParentView overlayView:pView];
1756 /* Return the freshly created overlay view */
1757 *ppView = pView;
1758 }
1759
1760 [pPool release];
1761}
1762
1763void cocoaViewReparent(NativeNSViewRef pView, NativeNSViewRef pParentView)
1764{
1765 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1766
1767 OverlayView* pOView = (OverlayView*)pView;
1768
1769 if (pOView)
1770 {
1771 /* Make sure the window is removed from any previous parent window. */
1772 if ([[pOView overlayWin] parentWindow] != nil)
1773 {
1774 [[[pOView overlayWin] parentWindow] removeChildWindow:[pOView overlayWin]];
1775 }
1776
1777 /* Set the new parent view */
1778 [pOView setParentView: pParentView];
1779
1780 /* Add the overlay window as a child to the new parent window */
1781 if (pParentView != nil)
1782 {
1783 [[pParentView window] addChildWindow:[pOView overlayWin] ordered:NSWindowAbove];
1784 if ([pOView isEverSized])
1785 [pOView performSelectorOnMainThread:@selector(vboxReshapeOnReparentPerform) withObject:nil waitUntilDone:NO];
1786 }
1787 }
1788
1789 [pPool release];
1790}
1791
1792void cocoaViewDestroy(NativeNSViewRef pView)
1793{
1794 NSWindow *pWin = nil;
1795
1796 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1797
1798 /* Hide the view early */
1799 [pView setHidden: YES];
1800
1801 pWin = [pView window];
1802 [[NSNotificationCenter defaultCenter] removeObserver:pWin];
1803 [pWin setContentView: nil];
1804 [[pWin parentWindow] removeChildWindow: pWin];
1805
1806 /*
1807 a = [pWin retainCount];
1808 for (; a > 1; --a)
1809 [pWin performSelector:@selector(release)]
1810 */
1811 /* We can NOT run synchronously with the main thread since this may lead to a deadlock,
1812 caused by main thread waiting xpcom thread, xpcom thread waiting to main hgcm thread,
1813 and main hgcm thread waiting for us, this is why use waitUntilDone:NO,
1814 which should cause no harm */
1815 [pWin performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO];
1816 /*
1817 [pWin release];
1818 */
1819
1820 /* We can NOT run synchronously with the main thread since this may lead to a deadlock,
1821 caused by main thread waiting xpcom thread, xpcom thread waiting to main hgcm thread,
1822 and main hgcm thread waiting for us, this is why use waitUntilDone:NO.
1823 We need to avoid concurrency though, so we cleanup some data right away via a cleanupData call */
1824 [(OverlayView*)pView cleanupData];
1825
1826 /* There seems to be a bug in the performSelector method which is called in
1827 * parentWindowChanged above. The object is retained but not released. This
1828 * results in an unbalanced reference count, which is here manually
1829 * decremented. */
1830 /*
1831 a = [pView retainCount];
1832 for (; a > 1; --a)
1833 */
1834 [pView performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO];
1835 /*
1836 [pView release];
1837 */
1838
1839 [pPool release];
1840}
1841
1842void cocoaViewShow(NativeNSViewRef pView, GLboolean fShowIt)
1843{
1844 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1845
1846 [pView setHidden: fShowIt==GL_TRUE?NO:YES];
1847
1848 [pPool release];
1849}
1850
1851void cocoaViewDisplay(NativeNSViewRef pView)
1852{
1853 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1854
1855 DEBUG_MSG_1(("cocoaViewDisplay %p\n", (void*)pView));
1856 [(OverlayView*)pView swapFBO];
1857
1858 [pPool release];
1859
1860}
1861
1862void cocoaViewSetPosition(NativeNSViewRef pView, NativeNSViewRef pParentView, int x, int y)
1863{
1864 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1865
1866 [(OverlayView*)pView setPos:NSMakePoint(x, y)];
1867
1868 [pPool release];
1869}
1870
1871void cocoaViewSetSize(NativeNSViewRef pView, int w, int h)
1872{
1873 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1874
1875 [(OverlayView*)pView setSize:NSMakeSize(w, h)];
1876
1877 [pPool release];
1878}
1879
1880void cocoaViewGetGeometry(NativeNSViewRef pView, int *pX, int *pY, int *pW, int *pH)
1881{
1882 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1883
1884 NSRect frame = [[pView window] frame];
1885 *pX = frame.origin.x;
1886 *pY = frame.origin.y;
1887 *pW = frame.size.width;
1888 *pH = frame.size.height;
1889
1890 [pPool release];
1891}
1892
1893void cocoaViewPresentComposition(NativeNSViewRef pView, const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pChangedEntry)
1894{
1895 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1896 NSOpenGLContext *pCtx;
1897
1898 /* view should not necesserily have a context set */
1899 pCtx = [(OverlayView*)pView glCtx];
1900 if (!pCtx)
1901 {
1902 ContextInfo * pCtxInfo = renderspuDefaultSharedContextAcquire();
1903 if (!pCtxInfo)
1904 {
1905 DEBUG_WARN(("renderspuDefaultSharedContextAcquire returned NULL"));
1906
1907 [pPool release];
1908 return;
1909 }
1910
1911 pCtx = pCtxInfo->context;
1912
1913 [(OverlayView*)pView setGLCtx:pCtx];
1914 }
1915
1916 [(OverlayView*)pView presentComposition:pChangedEntry];
1917
1918 [pPool release];
1919}
1920
1921void cocoaViewMakeCurrentContext(NativeNSViewRef pView, NativeNSOpenGLContextRef pCtx)
1922{
1923 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1924
1925 DEBUG_MSG(("cocoaViewMakeCurrentContext(%p, %p)\n", (void*)pView, (void*)pCtx));
1926
1927 if (pView)
1928 {
1929 [(OverlayView*)pView setGLCtx:pCtx];
1930 [(OverlayView*)pView makeCurrentFBO];
1931 }
1932 else
1933 {
1934 [NSOpenGLContext clearCurrentContext];
1935 }
1936
1937 [pPool release];
1938}
1939
1940void cocoaViewSetVisibleRegion(NativeNSViewRef pView, GLint cRects, const GLint* paRects)
1941{
1942 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1943
1944 [(OverlayView*)pView setVisibleRegions:cRects paRects:paRects];
1945
1946 [pPool release];
1947}
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