VirtualBox

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

Last change on this file since 23613 was 22509, checked in by vboxsync, 15 years ago

crOpenGL-OSX: Initial version for the Cocoa port.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 33.7 KB
Line 
1/** @file
2 *
3 * VirtualBox OpenGL Cocoa Window System Helper implementation
4 */
5
6/*
7 * Copyright (C) 2009 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22#include "renderspu_cocoa_helper.h"
23
24#include "chromium.h" /* For the visual bits of chromium */
25
26#include <iprt/thread.h>
27#include <iprt/string.h>
28
29/* Debug macros */
30#define FBO 1 /* Disable this to see how the output is without the FBO in the middle of the processing chain. */
31//#define SHOW_WINDOW_BACKGROUND 1 /* Define this to see the window background even if the window is clipped */
32//#define DEBUG_VERBOSE /* Define this could get some debug info about the messages flow. */
33
34#ifdef DEBUG_poetzsch
35#define DEBUG_MSG(text) \
36 printf text
37#else
38#define DEBUG_MSG(text) \
39 do {} while (0)
40#endif
41
42#ifdef DEBUG_VERBOSE
43#define DEBUG_MSG_1(text) \
44 DEBUG_MSG(text)
45#else
46#define DEBUG_MSG_1(text) \
47 do {} while (0)
48#endif
49
50#ifdef DEBUG_poetzsch
51#define CHECK_GL_ERROR()\
52 do \
53 { \
54 checkGLError(__FILE__, __LINE__); \
55 }while (0);
56
57 static void checkGLError(char *file, int line)
58 {
59 GLenum g = glGetError();
60 if (g != GL_NO_ERROR)
61 {
62 char *errStr;
63 switch (g)
64 {
65 case GL_INVALID_ENUM: errStr = RTStrDup("GL_INVALID_ENUM"); break;
66 case GL_INVALID_VALUE: errStr = RTStrDup("GL_INVALID_VALUE"); break;
67 case GL_INVALID_OPERATION: errStr = RTStrDup("GL_INVALID_OPERATION"); break;
68 case GL_STACK_OVERFLOW: errStr = RTStrDup("GL_STACK_OVERFLOW"); break;
69 case GL_STACK_UNDERFLOW: errStr = RTStrDup("GL_STACK_UNDERFLOW"); break;
70 case GL_OUT_OF_MEMORY: errStr = RTStrDup("GL_OUT_OF_MEMORY"); break;
71 case GL_TABLE_TOO_LARGE: errStr = RTStrDup("GL_TABLE_TOO_LARGE"); break;
72 default: errStr = RTStrDup("UNKOWN"); break;
73 }
74 DEBUG_MSG(("%s:%d: glError %d (%s)\n", file, line, g, errStr));
75 RTMemFree(errStr);
76 }
77 }
78#else
79#define CHECK_GL_ERROR()\
80 do {} while (0)
81#endif
82
83#define GL_SAVE_STATE \
84do \
85{ \
86 glPushAttrib(GL_ALL_ATTRIB_BITS); \
87 glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS); \
88 glMatrixMode(GL_PROJECTION); \
89 glPushMatrix(); \
90 glMatrixMode(GL_TEXTURE); \
91 glPushMatrix(); \
92 glMatrixMode(GL_COLOR); \
93 glPushMatrix(); \
94 glMatrixMode(GL_MODELVIEW); \
95 glPushMatrix(); \
96} \
97while(0);
98
99#define GL_RESTORE_STATE \
100do \
101{ \
102 glMatrixMode(GL_MODELVIEW); \
103 glPopMatrix(); \
104 glMatrixMode(GL_COLOR); \
105 glPopMatrix(); \
106 glMatrixMode(GL_TEXTURE); \
107 glPopMatrix(); \
108 glMatrixMode(GL_PROJECTION); \
109 glPopMatrix(); \
110 glPopClientAttrib(); \
111 glPopAttrib(); \
112} \
113while(0);
114
115/* Custom OpenGL context class. This implementation doesn't allow to set a view
116 * to the context, but save the view for later use. Also it saves a copy of the
117 * pixel format used to create that context for later use. */
118@interface OverlayOpenGLContext: NSOpenGLContext
119{
120@private
121 NSOpenGLPixelFormat *m_pPixelFormat;
122 NSView *m_pView;
123}
124- (NSOpenGLPixelFormat*)openGLPixelFormat;
125@end
126
127/* The custom view class. This is the main class of the cocoa OpenGL
128 * implementation. It manages an frame buffer object for the rendering of the
129 * guest applications. The guest applications render in this frame buffer which
130 * is bind to an OpenGL texture. To display the guest content, an secondary
131 * shared OpenGL context of the main OpenGL context is created. The secondary
132 * context is marked as non opaque & the texture is displayed on an object
133 * which is composed out of the several visible region rectangles. */
134@interface OverlayView: NSView
135{
136@private
137 NSView *m_pParentView;
138
139 NSOpenGLContext *m_pGLCtx;
140 NSOpenGLContext *m_pSharedGLCtx;
141 RTTHREAD mThread;
142
143 /* FBO handling */
144 GLuint m_FBOId;
145 GLuint m_FBOTexId;
146 NSSize m_FBOTexSize;
147 GLuint m_FBODepthId;
148 GLuint m_FBOStencilId;
149 GLuint m_FBODepthStencilPackedId;
150
151 /* For clipping */
152 GLint m_cClipRects;
153 GLint *m_paClipRects;
154
155 /* Position/Size tracking */
156 NSPoint m_Pos;
157 NSSize m_Size;
158
159 NSPoint m_RootShift;
160}
161- (id)initWithFrame:(NSRect)frame thread:(RTTHREAD)aThread parentView:(NSView*)pParentView;
162- (void)setGLCtx:(NSOpenGLContext*)pCtx;
163- (NSOpenGLContext*)glCtx;
164
165- (void)setPos:(NSPoint)pos;
166- (NSPoint)pos;
167- (void)setSize:(NSSize)size;
168- (NSSize)size;
169- (void)reshape;
170
171- (void)createFBO;
172- (void)deleteFBO;
173
174- (void)updateFBO;
175- (void)makeCurrentFBO;
176- (void)swapFBO;
177- (void)flushFBO;
178- (void)finishFBO;
179- (void)bindFBO;
180- (void)renderFBOToView;
181
182- (void)clearVisibleRegions;
183- (void)setVisibleRegions:(GLint)cRects paRects:(GLint*)paRects;
184@end
185
186/* Helper view. This view is added as a sub view of the parent view to track
187 * main window changes. Whenever the main window is changed (which happens on
188 * fullscreen/seamless entry/exit) the overlay window is informed & can add
189 * them self as a child window again. */
190@class OverlayWindow;
191@interface OverlayHelperView: NSView
192{
193@private
194 OverlayWindow *m_pOverlayWindow;
195}
196-(id)initWithOverlayWindow:(OverlayWindow*)pOverlayWindow;
197@end
198
199/* Custom window class. This is the overlay window which contains our custom
200 * NSView. Its a direct child of the Qt Main window. It marks its background
201 * transparent & non opaque to make clipping possible. It also disable mouse
202 * events and handle frame change events of the parent view. */
203@interface OverlayWindow: NSWindow
204{
205@private
206 NSView *m_pParentView;
207 OverlayView *m_pOverlayView;
208 OverlayHelperView *m_pOverlayHelperView;
209}
210- (id)initWithParentView:(NSView*)pParentView overlayView:(OverlayView*)pOverlayView;
211- (void)parentWindowFrameChanged:(NSNotification *)note;
212- (void)parentWindowChanged:(NSWindow*)pWindow;
213@end
214
215/********************************************************************************
216*
217* OverlayOpenGLContext class implementation
218*
219********************************************************************************/
220@implementation OverlayOpenGLContext
221
222-(id)initWithFormat:(NSOpenGLPixelFormat*)format shareContext:(NSOpenGLContext*)share
223{
224 m_pPixelFormat = NULL;
225 m_pView = NULL;
226
227 self = [super initWithFormat:format shareContext:share];
228 if (self)
229 m_pPixelFormat = format;
230
231 return self;
232}
233
234- (void)dealloc
235{
236 DEBUG_MSG(("Dealloc context %X\n", (uint)self));
237
238 [m_pPixelFormat release];
239
240 [super dealloc];
241}
242
243-(void)setView:(NSView*)view
244{
245#ifdef FBO
246 m_pView = view;;
247#else
248 [super setView: view];
249#endif
250}
251
252-(NSView*)view
253{
254#ifdef FBO
255 return m_pView;
256#else
257 return [super view];
258#endif
259}
260
261-(void)clearDrawable
262{
263 m_pView = NULL;;
264 [super clearDrawable];
265}
266
267-(NSOpenGLPixelFormat*)openGLPixelFormat
268{
269 return m_pPixelFormat;
270}
271
272@end;
273
274/********************************************************************************
275*
276* OverlayHelperView class implementation
277*
278********************************************************************************/
279@implementation OverlayHelperView
280
281-(id)initWithOverlayWindow:(OverlayWindow*)pOverlayWindow
282{
283 self = [super initWithFrame:NSZeroRect];
284
285 m_pOverlayWindow = pOverlayWindow;
286
287 return self;
288}
289
290-(void)viewDidMoveToWindow
291{
292 [m_pOverlayWindow parentWindowChanged:[self window]];
293}
294
295@end
296
297/********************************************************************************
298*
299* OverlayWindow class implementation
300*
301********************************************************************************/
302@implementation OverlayWindow
303
304- (id)initWithParentView:(NSView*)pParentView overlayView:(OverlayView*)pOverlayView
305{
306 if(self = [super initWithContentRect:NSZeroRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO])
307 {
308 m_pParentView = pParentView;
309 m_pOverlayView = pOverlayView;
310
311 m_pOverlayHelperView = [[OverlayHelperView alloc] initWithOverlayWindow:self];
312 /* Add the helper view as a child of the parent view to get notifications */
313 [pParentView addSubview:m_pOverlayHelperView];
314
315 /* Make sure this window is transparent */
316#ifdef SHOW_WINDOW_BACKGROUND
317 /* For debugging */
318 [self setBackgroundColor:[NSColor colorWithCalibratedRed:1.0 green:0.0 blue:0.0 alpha:0.7]];
319#else
320 [self setBackgroundColor:[NSColor clearColor]];
321#endif
322 [self setOpaque:NO];
323 [self setAlphaValue:.999];
324 /* Disable mouse events for this window */
325 [self setIgnoresMouseEvents:YES];
326
327 NSWindow *pParentWin = [m_pParentView window];
328
329 /* Initial set the position to the parents view top/left (Compiz fix). */
330 [self setFrameOrigin:
331 [pParentWin convertBaseToScreen:
332 [m_pParentView convertPoint:NSZeroPoint toView:nil]]];
333
334 /* Set the overlay view as out content view */
335 [self setContentView:m_pOverlayView];
336
337 /* Add ourself as a child to the parent views window */
338 [pParentWin addChildWindow:self ordered:NSWindowAbove];
339
340 /* Ask to get notifications when our parent window frame changes. */
341 [[NSNotificationCenter defaultCenter]
342 addObserver:self
343 selector:@selector(parentWindowFrameChanged:)
344 name:NSWindowDidResizeNotification
345 object:pParentWin];
346 }
347 return self;
348}
349
350- (void)dealloc
351{
352 DEBUG_MSG(("Dealloc window %X\n", (uint)self));
353
354 [m_pOverlayHelperView removeFromSuperview];
355
356 [m_pOverlayHelperView release];
357
358 [super dealloc];
359}
360
361- (void)parentWindowFrameChanged:(NSNotification*)pNote
362{
363 /* Reposition this window with the help of the OverlayView */
364 [m_pOverlayView reshape];
365}
366
367- (void)parentWindowChanged:(NSWindow*)pWindow
368{
369 if(pWindow)
370 {
371 /* Ask to get notifications when our parent window frame changes. */
372 [[NSNotificationCenter defaultCenter]
373 addObserver:self
374 selector:@selector(parentWindowFrameChanged:)
375 name:NSWindowDidResizeNotification
376 object:pWindow];
377 /* Add us self as child window */
378 [pWindow addChildWindow:self ordered:NSWindowAbove];
379 /* Reshape the overlay view after a short waiting time to let the main
380 * window resize itself properly. */
381 [m_pOverlayView performSelector:@selector(reshape) withObject:nil afterDelay:0.2];
382 }
383}
384
385@end
386
387/********************************************************************************
388*
389* OverlayView class implementation
390*
391********************************************************************************/
392@implementation OverlayView
393
394- (id)initWithFrame:(NSRect)frame thread:(RTTHREAD)aThread parentView:(NSView*)pParentView
395{
396 m_pParentView = pParentView;
397 /* Make some reasonable defaults */
398 m_pGLCtx = NULL;
399 m_pSharedGLCtx = NULL;
400 mThread = aThread;
401 m_FBOId = 0;
402 m_FBOTexId = 0;
403 m_FBOTexSize = NSZeroSize;
404 m_FBODepthId = 0;
405 m_FBOStencilId = 0;
406 m_FBODepthStencilPackedId = 0;
407 m_cClipRects = 0;
408 m_paClipRects = NULL;
409 m_Pos = NSZeroPoint;
410 m_Size = NSZeroSize;
411 m_RootShift = NSZeroPoint;
412
413 DEBUG_MSG(("Init view %X (%X)\n", (uint)self, (uint)mThread));
414
415 self = [super initWithFrame:frame];
416
417 return self;
418}
419
420- (void)dealloc
421{
422 DEBUG_MSG(("Dealloc view %X\n", (uint)self));
423
424 [self deleteFBO];
425
426 if (m_pGLCtx)
427 {
428 if ([m_pGLCtx view] == self)
429 [m_pGLCtx clearDrawable];
430 }
431 if (m_pSharedGLCtx)
432 {
433 if ([m_pSharedGLCtx view] == self)
434 [m_pSharedGLCtx clearDrawable];
435
436 [m_pSharedGLCtx release];
437 }
438
439 [self clearVisibleRegions];
440
441 [super dealloc];
442}
443
444- (void)drawRect:(NSRect)aRect
445{
446// NSGraphicsContext*pC = [NSGraphicsContext currentContext];
447// [[NSColor blueColor] set];
448// NSBezierPath *p = [[NSBezierPath alloc] bezierPathWithOvalInRect:[self frame]];
449// [p fill];
450// [[NSColor greenColor] set];
451// [p stroke];
452// if ([self lockFocusIfCanDraw])
453// {
454// [self renderFBOToView];
455// [self unlockFocus];
456// }
457}
458
459- (void)setGLCtx:(NSOpenGLContext*)pCtx
460{
461 m_pGLCtx = pCtx;
462}
463
464- (NSOpenGLContext*)glCtx
465{
466 return m_pGLCtx;
467}
468
469- (void)setPos:(NSPoint)pos
470{
471 m_Pos = pos;
472 [self reshape];
473}
474
475- (NSPoint)pos
476{
477 return m_Pos;
478}
479
480- (void)setSize:(NSSize)size
481{
482 m_Size = size;
483 [self reshape];
484 [self updateFBO];
485}
486
487- (NSSize)size
488{
489 return m_Size;
490}
491
492- (void)reshape
493{
494 /* Getting the right screen coordinates of the parents frame is a little bit
495 * complicated. */
496 NSRect parentFrame = [m_pParentView frame];
497 NSPoint parentPos = [[m_pParentView window] convertBaseToScreen:[[m_pParentView superview] convertPointToBase:NSMakePoint(parentFrame.origin.x, parentFrame.origin.y + parentFrame.size.height)]];
498 parentFrame.origin.x = parentPos.x;
499 parentFrame.origin.y = parentPos.y;
500
501 /* Calculate the new screen coordinates of the overlay window. */
502 NSPoint childPos = NSMakePoint(m_Pos.x, m_Pos.y + m_Size.height);
503 childPos = [[m_pParentView window] convertBaseToScreen:[[m_pParentView superview] convertPointToBase:childPos]];
504
505 /* Make a frame out of it. */
506 NSRect childFrame = NSMakeRect(childPos.x, childPos.y, m_Size.width, m_Size.height);
507
508 /* We have to make sure that the overlay window will not be displayed out
509 * of the parent window. So intersect both frames & use the result as the new
510 * frame for the window. */
511 NSRect newFrame = NSIntersectionRect(parentFrame, childFrame);
512
513 /* Later we have to correct the texture position in the case the window is
514 * out of the parents window frame. So save the shift values for later use. */
515 if (parentFrame.origin.x > childFrame.origin.x)
516 m_RootShift.x = parentFrame.origin.x - childFrame.origin.x;
517 else
518 m_RootShift.x = 0;
519 if (parentFrame.origin.y > childFrame.origin.y)
520 m_RootShift.y = parentFrame.origin.y - childFrame.origin.y;
521 else
522 m_RootShift.y = 0;
523
524// NSScrollView *pScrollView = [[[m_pParentView window] contentView] enclosingScrollView];
525// if (pScrollView)
526// {
527// NSRect scrollRect = [pScrollView documentVisibleRect];
528// NSRect scrollRect = [m_pParentView visibleRect];
529// printf ("sc rect: %d %d %d %d\n", (int) scrollRect.origin.x,(int) scrollRect.origin.y,(int) scrollRect.size.width,(int) scrollRect.size.height);
530// NSRect b = [[m_pParentView superview] bounds];
531// printf ("bound rect: %d %d %d %d\n", (int) b.origin.x,(int) b.origin.y,(int) b.size.width,(int) b.size.height);
532// newFrame.origin.x += scrollRect.origin.x;
533// newFrame.origin.y += scrollRect.origin.y;
534// }
535
536 /* Set the new frame. */
537 [[self window] setFrame:newFrame display:YES];
538}
539
540- (void)createFBO
541{
542 [self deleteFBO];
543
544 GL_SAVE_STATE;
545
546 /* If not previously setup generate IDs for FBO and its associated texture. */
547 if (!m_FBOId)
548 {
549 /* Make sure the framebuffer extension is supported */
550 const GLubyte* strExt;
551 GLboolean isFBO;
552 /* Get the extension name string. It is a space-delimited list of the
553 * OpenGL extensions that are supported by the current renderer. */
554 strExt = glGetString(GL_EXTENSIONS);
555 isFBO = gluCheckExtension((const GLubyte*)"GL_EXT_framebuffer_object", strExt);
556 if (!isFBO)
557 {
558 DEBUG_MSG(("Your system does not support framebuffer extension\n"));
559 }
560
561 /* Create FBO object */
562 glGenFramebuffersEXT(1, &m_FBOId);
563 /* & the texture as well the depth/stencil render buffer */
564 glGenTextures(1, &m_FBOTexId);
565 DEBUG_MSG_1(("Create FBO %d %d\n", m_FBOId, m_FBOTexId));
566
567// glGenRenderbuffersEXT(1, &m_FBODepthId);
568// glGenRenderbuffersEXT(1, &m_FBOStencilId);
569 glGenRenderbuffersEXT(1, &m_FBODepthStencilPackedId);
570 }
571
572 m_FBOTexSize = m_Size;
573 /* Bind to FBO */
574 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FBOId);
575
576 glEnable(GL_TEXTURE_RECTANGLE_ARB);
577
578 GLfloat imageAspectRatio = m_FBOTexSize.width / m_FBOTexSize.height;
579
580 /* Sanity check against maximum OpenGL texture size. If bigger adjust to
581 * maximum possible size while maintain the aspect ratio. */
582 GLint maxTexSize;
583 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize);
584// maxTexSize = 150;
585 GLint filter = GL_NEAREST;
586 if (m_FBOTexSize.width > maxTexSize || m_FBOTexSize.height > maxTexSize)
587 {
588 filter = GL_NICEST;
589 if (imageAspectRatio > 1)
590 {
591 m_FBOTexSize.width = maxTexSize;
592 m_FBOTexSize.height = maxTexSize / imageAspectRatio;
593 }
594 else
595 {
596 m_FBOTexSize.width = maxTexSize * imageAspectRatio;
597 m_FBOTexSize.height = maxTexSize;
598 }
599 }
600
601 /* Initialize FBO Texture */
602 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_FBOTexId);
603 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, filter);
604 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, filter);
605 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP);
606 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP);
607
608 /* The GPUs like the GL_BGRA / GL_UNSIGNED_INT_8_8_8_8_REV combination
609 * others are also valid, but might incur a costly software translation. */
610 glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, m_FBOTexSize.width, m_FBOTexSize.height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
611
612 /* Now attach texture to the FBO as its color destination */
613 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, m_FBOTexId, 0);
614// glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
615
616 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_FBODepthStencilPackedId);
617 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_STENCIL_EXT, m_FBOTexSize.width, m_FBOTexSize.height);
618 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_FBODepthStencilPackedId);
619 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_FBODepthStencilPackedId);
620
621// glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_FBODepthId);
622// glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, r.size.width, r.size.height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
623// glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, m_FBODepthId, 0);
624//
625// glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_FBOStencilId);
626// glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, r.size.width, r.size.height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
627// glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, m_FBOStencilId, 0);
628
629 /* Initialize Depth Render Buffer */
630// glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_FBODepthId);
631// glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, r.size.width, r.size.height);
632 /* and attach it to the FBO */
633// glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_FBODepthId);
634//
635// glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_FBOStencilId);
636// glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX, r.size.width, r.size.height);
637// glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_FBOStencilId);
638
639// glClearColor (clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
640// glClearColor (0, 0, 0, 0);
641// glClear(GL_COLOR_BUFFER_BIT);
642
643 /* Make sure the FBO was created succesfully. */
644 if (GL_FRAMEBUFFER_COMPLETE_EXT != glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT))
645 DEBUG_MSG(("Framebuffer Object creation or update failed!\n"));
646
647 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
648 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
649
650 /* Initialize with one big visual region over the full size */
651 [self clearVisibleRegions];
652 m_cClipRects = 1;
653 m_paClipRects = (GLint*)RTMemAlloc(sizeof(GLint) * 4);
654 m_paClipRects[0] = 0;
655 m_paClipRects[1] = 0;
656 m_paClipRects[2] = m_FBOTexSize.width;
657 m_paClipRects[3] = m_FBOTexSize.height;
658
659 GL_RESTORE_STATE;
660}
661
662- (void)deleteFBO
663{
664 if ([NSOpenGLContext currentContext] != nil)
665 {
666 GL_SAVE_STATE;
667
668 if (m_FBODepthId > 0)
669 {
670 glDeleteRenderbuffersEXT(1, &m_FBODepthId);
671 m_FBODepthId = 0;
672 }
673 if (m_FBOStencilId > 0)
674 {
675 glDeleteRenderbuffersEXT(1, &m_FBOStencilId);
676 m_FBOStencilId = 0;
677 }
678 if (m_FBODepthStencilPackedId > 0)
679 {
680 glDeleteRenderbuffersEXT(1, &m_FBODepthStencilPackedId);
681 m_FBODepthStencilPackedId = 0;
682 }
683 if (m_FBOTexId > 0)
684 {
685 glEnable(GL_TEXTURE_RECTANGLE_ARB);
686 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
687 glDeleteTextures(1, &m_FBOTexId);
688 m_FBOTexId = 0;
689 }
690 if (m_FBOId > 0)
691 {
692 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
693
694 glDeleteFramebuffersEXT(1, &m_FBOId);
695 m_FBOId = 0;
696 }
697
698 GL_RESTORE_STATE;
699 }
700}
701
702- (void)updateFBO
703{
704 [self makeCurrentFBO];
705
706 if (m_pGLCtx)
707 {
708#ifdef FBO
709 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
710 [self createFBO];
711 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FBOId);
712#endif
713 [m_pGLCtx update];
714 }
715}
716
717- (void)makeCurrentFBO
718{
719 DEBUG_MSG_1(("MakeCurrent called %X\n", self));
720
721#ifdef FBO
722 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FBOId);
723#endif
724 if (m_pGLCtx)
725 {
726 if ([m_pGLCtx view] != self)
727 {
728 /* We change the active view, so flush first */
729 glFlush();
730 [m_pGLCtx setView: self];
731 CHECK_GL_ERROR();
732 }
733// if ([NSOpenGLContext currentContext] != m_pGLCtx)
734 {
735 [m_pGLCtx makeCurrentContext];
736 CHECK_GL_ERROR();
737// [m_pGLCtx update];
738 }
739 }
740#ifdef FBO
741 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FBOId);
742#endif
743}
744
745- (void)swapFBO
746{
747 DEBUG_MSG_1(("SwapCurrent called %X\n", self));
748
749#ifdef FBO
750 [m_pGLCtx flushBuffer];
751// glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
752 if ([self lockFocusIfCanDraw])
753 {
754 [self renderFBOToView];
755 [self unlockFocus];
756 }
757// glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FBOId);
758#else
759 [m_pGLCtx flushBuffer];
760#endif
761}
762
763- (void)flushFBO
764{
765 glFlush();
766// glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
767 if ([self lockFocusIfCanDraw])
768 {
769 [self renderFBOToView];
770 [self unlockFocus];
771 }
772// glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FBOId);
773}
774
775- (void)finishFBO
776{
777 glFinish();
778// glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
779 if ([self lockFocusIfCanDraw])
780 {
781 [self renderFBOToView];
782 [self unlockFocus];
783 }
784// glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FBOId);
785}
786
787- (void)bindFBO
788{
789 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FBOId);
790}
791
792- (void)renderFBOToView
793{
794 if (!m_pSharedGLCtx)
795 {
796 /* Create a shared context out of the main context. Use the same pixel format. */
797 m_pSharedGLCtx = [[NSOpenGLContext alloc] initWithFormat:[(OverlayOpenGLContext*)m_pGLCtx openGLPixelFormat] shareContext:m_pGLCtx];
798
799 /* Set the new context as non opaque */
800 GLint opaque = 0;
801 [m_pSharedGLCtx setValues:&opaque forParameter:NSOpenGLCPSurfaceOpacity];
802 /* Only swap on screen refresh */
803// GLint swap = 1;
804// [m_pSharedGLCtx setValues:&swap forParameter:NSOpenGLCPSwapInterval];
805 /* Set this view as the drawable for the new context */
806 [m_pSharedGLCtx setView: self];
807 }
808
809 if (m_pSharedGLCtx)
810 {
811 if (m_FBOTexId > 0)
812 {
813 [m_pSharedGLCtx makeCurrentContext];
814 [m_pSharedGLCtx update];
815
816// printf ("renderFBOToView\n");
817// CGLLockContext([m_pGLCtx CGLContextObj]);
818 NSRect r = [self frame];
819
820 GL_SAVE_STATE;
821
822 /* Setup all matrices */
823 glMatrixMode(GL_PROJECTION);
824 glLoadIdentity();
825 glViewport(0, 0, r.size.width, r.size.height);
826 glOrtho(0, r.size.width, 0, r.size.height, -1, 1);
827 glMatrixMode(GL_TEXTURE);
828 glLoadIdentity();
829 glTranslatef(0.0f, m_RootShift.y, 0.0f);
830 glMatrixMode(GL_MODELVIEW);
831 glLoadIdentity();
832 glTranslatef(-m_RootShift.x, 0.0f, 0.0f);
833
834 /* Clear background to transparent */
835 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
836 glClear(GL_COLOR_BUFFER_BIT);
837
838 glEnable(GL_TEXTURE_RECTANGLE_ARB);
839 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_FBOTexId);
840 GLint i;
841 for (i = 0; i < m_cClipRects; ++i)
842 {
843 GLint x1 = m_paClipRects[4*i];
844 GLint y1 = r.size.height - m_paClipRects[4*i+1];
845 GLint x2 = m_paClipRects[4*i+2];
846 GLint y2 = r.size.height - m_paClipRects[4*i+3];
847 glBegin(GL_QUADS);
848 {
849 glTexCoord2i(x1, y1); glVertex2i(x1, y1);
850 glTexCoord2i(x1, y2); glVertex2i(x1, y2);
851 glTexCoord2i(x2, y2); glVertex2i(x2, y2);
852 glTexCoord2i(x2, y1); glVertex2i(x2, y1);
853 }
854 glEnd();
855 }
856
857 [m_pSharedGLCtx flushBuffer];
858
859 GL_RESTORE_STATE;
860 [m_pGLCtx makeCurrentContext];
861 [m_pGLCtx update];
862// CGLUnlockContext([m_pGLCtx CGLContextObj]);
863 }
864 }
865}
866
867- (void)clearVisibleRegions
868{
869 if(m_paClipRects)
870 {
871 RTMemFree(m_paClipRects);
872 m_paClipRects = NULL;
873 }
874 m_cClipRects = 0;
875}
876
877- (void)setVisibleRegions:(GLint)cRects paRects:(GLint*)paRects
878{
879 DEBUG_MSG_1(("New region recieved\n"));
880
881 [self clearVisibleRegions];
882
883 if (cRects>0)
884 {
885 m_paClipRects = (GLint*)RTMemAlloc(sizeof(GLint) * 4 * cRects);
886 m_cClipRects = cRects;
887 memcpy(m_paClipRects, paRects, sizeof(GLint) * 4 * cRects);
888 }
889}
890
891@end
892
893/********************************************************************************
894*
895* OpenGL context management
896*
897********************************************************************************/
898void cocoaGLCtxCreate(NativeGLCtxRef *ppCtx, GLbitfield fVisParams)
899{
900 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
901
902 NSOpenGLPixelFormatAttribute attribs[24] =
903 {
904 NSOpenGLPFAWindow,
905 NSOpenGLPFAAccelerated,
906 NSOpenGLPFAColorSize, (NSOpenGLPixelFormatAttribute)24
907 };
908
909 int i = 4;
910 if (fVisParams & CR_ALPHA_BIT)
911 {
912 DEBUG_MSG(("CR_ALPHA_BIT requested\n"));
913 attribs[i++] = NSOpenGLPFAAlphaSize;
914 attribs[i++] = 8;
915 }
916 if (fVisParams & CR_DEPTH_BIT)
917 {
918 DEBUG_MSG(("CR_DEPTH_BIT requested\n"));
919 attribs[i++] = NSOpenGLPFADepthSize;
920 attribs[i++] = 24;
921 }
922 if (fVisParams & CR_STENCIL_BIT)
923 {
924 DEBUG_MSG(("CR_STENCIL_BIT requested\n"));
925 attribs[i++] = NSOpenGLPFAStencilSize;
926 attribs[i++] = 8;
927 }
928 if (fVisParams & CR_ACCUM_BIT)
929 {
930 DEBUG_MSG(("CR_ACCUM_BIT requested\n"));
931 attribs[i++] = NSOpenGLPFAAccumSize;
932 if (fVisParams & CR_ALPHA_BIT)
933 attribs[i++] = 32;
934 else
935 attribs[i++] = 24;
936 }
937 if (fVisParams & CR_MULTISAMPLE_BIT)
938 {
939 DEBUG_MSG(("CR_MULTISAMPLE_BIT requested\n"));
940 attribs[i++] = NSOpenGLPFASampleBuffers;
941 attribs[i++] = 1;
942 attribs[i++] = NSOpenGLPFASamples;
943 attribs[i++] = 4;
944 }
945 if (fVisParams & CR_DOUBLE_BIT)
946 {
947 DEBUG_MSG(("CR_DOUBLE_BIT requested\n"));
948 attribs[i++] = NSOpenGLPFADoubleBuffer;
949 }
950 if (fVisParams & CR_STEREO_BIT)
951 {
952 DEBUG_MSG(("CR_DOUBLE_BIT requested\n"));
953 attribs[i++] = NSOpenGLPFAStereo;
954 }
955
956 /* Mark the end */
957 attribs[i++] = 0;
958
959 /* Choose a pixel format */
960 NSOpenGLPixelFormat* pFmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
961
962 if (pFmt)
963 {
964 *ppCtx = [[OverlayOpenGLContext alloc] initWithFormat:pFmt shareContext:nil];
965
966 /* Enable multi threaded OpenGL engine */
967// CGLContextObj cglCtx = [*ppCtx CGLContextObj];
968// CGLError err = CGLEnable(cglCtx, kCGLCEMPEngine);
969// if (err != kCGLNoError)
970// printf ("Couldn't enable MT OpenGL engine!\n");
971
972 DEBUG_MSG(("New context %X\n", (uint)*ppCtx));
973 }
974
975 [pPool release];
976}
977
978void cocoaGLCtxDestroy(NativeGLCtxRef pCtx)
979{
980 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
981
982// [pCtx release];
983
984 [pPool release];
985}
986
987/********************************************************************************
988*
989* View management
990*
991********************************************************************************/
992void cocoaViewCreate(NativeViewRef *ppView, NativeViewRef pParentView, GLbitfield fVisParams)
993{
994 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
995
996 /* Create our worker view */
997 OverlayView* pView = [[OverlayView alloc] initWithFrame:NSZeroRect thread:RTThreadSelf() parentView:pParentView];
998
999 if (pView)
1000 {
1001 /* We need a real window as container for the view */
1002 [[OverlayWindow alloc] initWithParentView:pParentView overlayView:pView];
1003 /* Return the freshly created overlay view */
1004 *ppView = pView;
1005 }
1006
1007 [pPool release];
1008}
1009
1010void cocoaViewDestroy(NativeViewRef pView)
1011{
1012 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1013
1014 [pView setHidden: YES];
1015
1016 NSWindow *win = [pView window];
1017 [win setContentView:nil];
1018 [[win parentWindow] removeChildWindow: win];
1019
1020 [win release];
1021 [pView release];
1022
1023 [pPool release];
1024}
1025
1026void cocoaViewShow(NativeViewRef pView, GLboolean fShowIt)
1027{
1028 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1029
1030 [pView setHidden: fShowIt==GL_TRUE?NO:YES];
1031
1032 [pPool release];
1033}
1034
1035void cocoaViewDisplay(NativeViewRef pView)
1036{
1037 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1038
1039 [(OverlayView*)pView swapFBO];
1040
1041 [pPool release];
1042
1043}
1044
1045void cocoaViewSetPosition(NativeViewRef pView, NativeViewRef pParentView, int x, int y)
1046{
1047 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1048
1049 [(OverlayView*)pView setPos:NSMakePoint(x, y)];
1050
1051 [pPool release];
1052}
1053
1054void cocoaViewSetSize(NativeViewRef pView, int w, int h)
1055{
1056 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1057
1058 [(OverlayView*)pView setSize:NSMakeSize(w, h)];
1059
1060 [pPool release];
1061}
1062
1063void cocoaViewGetGeometry(NativeViewRef pView, int *pX, int *pY, int *pW, int *pH)
1064{
1065 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1066
1067 NSRect frame = [[pView window] frame];
1068 *pX = frame.origin.x;
1069 *pY = frame.origin.y;
1070 *pW = frame.size.width;
1071 *pH = frame.size.height;
1072
1073 [pPool release];
1074}
1075
1076void cocoaViewMakeCurrentContext(NativeViewRef pView, NativeGLCtxRef pCtx)
1077{
1078 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1079
1080 [(OverlayView*)pView setGLCtx:pCtx];
1081 [(OverlayView*)pView makeCurrentFBO];
1082
1083 [pPool release];
1084}
1085
1086void cocoaViewSetVisibleRegion(NativeViewRef pView, GLint cRects, GLint* paRects)
1087{
1088 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1089
1090 [(OverlayView*)pView setVisibleRegions:cRects paRects:paRects];
1091
1092 [pPool release];
1093}
1094
1095/********************************************************************************
1096*
1097* Additional OpenGL wrapper
1098*
1099********************************************************************************/
1100void cocoaFlush()
1101{
1102 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1103
1104// glFlush();
1105// return;
1106
1107 DEBUG_MSG_1(("glFlush called\n"));
1108
1109#ifdef FBO
1110 NSOpenGLContext *pCtx = [NSOpenGLContext currentContext];
1111 if (pCtx)
1112 {
1113 NSView *pView = [pCtx view];
1114 if (pView)
1115 {
1116 if ([pView respondsToSelector:@selector(flushFBO)])
1117 [pView performSelector:@selector(flushFBO)];
1118 }
1119 }
1120#else
1121 glFlush();
1122#endif
1123
1124 [pPool release];
1125}
1126
1127void cocoaFinish()
1128{
1129 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1130
1131 DEBUG_MSG_1(("glFinish called\n"));
1132
1133#ifdef FBO
1134 NSOpenGLContext *pCtx = [NSOpenGLContext currentContext];
1135 if (pCtx)
1136 {
1137 NSView *pView = [pCtx view];
1138 if (pView)
1139 {
1140 if ([pView respondsToSelector:@selector(finishFBO)])
1141 [pView performSelector:@selector(finishFBO)];
1142 }
1143 }
1144#else
1145 glFinish();
1146#endif
1147
1148 [pPool release];
1149}
1150
1151void cocoaBindFramebufferEXT(GLenum target, GLuint framebuffer)
1152{
1153 NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1154
1155 DEBUG_MSG_1(("glRenderspuBindFramebufferEXT called %d\n", framebuffer));
1156
1157#ifdef FBO
1158 if (framebuffer != 0)
1159 glBindFramebufferEXT(target, framebuffer);
1160 else
1161 {
1162 NSOpenGLContext *pCtx = [NSOpenGLContext currentContext];
1163 if (pCtx)
1164 {
1165 NSView *pView = [pCtx view];
1166 if (pView)
1167 {
1168 if ([pView respondsToSelector:@selector(bindFBO)])
1169 [pView performSelector:@selector(bindFBO)];
1170 }
1171 }
1172 }
1173#else
1174 glBindFramebufferEXT(target, framebuffer);
1175#endif
1176
1177 [pPool release];
1178}
1179
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