renderspu_cocoa_helper.m revision 610972deee47d5e5229ccdb6c86cbb332d2b4626
/** @file
*
* VirtualBox OpenGL Cocoa Window System Helper implementation
*/
/*
* Copyright (C) 2009 Sun Microsystems, Inc.
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 USA or visit http://www.sun.com if you need
* additional information or have any questions.
*/
#include "renderspu_cocoa_helper.h"
/* Debug macros */
#define FBO 1 /* Disable this to see how the output is without the FBO in the middle of the processing chain. */
//#define SHOW_WINDOW_BACKGROUND 1 /* Define this to see the window background even if the window is clipped */
//#define DEBUG_VERBOSE /* Define this could get some debug info about the messages flow. */
#else
do {} while (0)
#else
do {} while (0)
#define CHECK_GL_ERROR()\
do \
{ \
}while (0);
{
GLenum g = glGetError();
if (g != GL_NO_ERROR)
{
char *errStr;
switch (g)
{
}
}
}
#else
#define CHECK_GL_ERROR()\
do {} while (0)
do \
{ \
glPushMatrix(); \
glPushMatrix(); \
glMatrixMode(GL_COLOR); \
glPushMatrix(); \
glPushMatrix(); \
} \
while(0);
do \
{ \
glPopMatrix(); \
glMatrixMode(GL_COLOR); \
glPopMatrix(); \
glPopMatrix(); \
glPopMatrix(); \
glPopClientAttrib(); \
glPopAttrib(); \
} \
while(0);
/* Custom OpenGL context class. This implementation doesn't allow to set a view
* to the context, but save the view for later use. Also it saves a copy of the
* pixel format used to create that context for later use. */
@interface OverlayOpenGLContext: NSOpenGLContext
{
@private
}
@end
/* The custom view class. This is the main class of the cocoa OpenGL
* implementation. It manages an frame buffer object for the rendering of the
* guest applications. The guest applications render in this frame buffer which
* is bind to an OpenGL texture. To display the guest content, an secondary
* shared OpenGL context of the main OpenGL context is created. The secondary
* context is marked as non opaque & the texture is displayed on an object
* which is composed out of the several visible region rectangles. */
@interface OverlayView: NSView
{
@private
/* FBO handling */
/* For clipping */
}
- (NSOpenGLContext*)glCtx;
- (void)reshape;
- (void)createFBO;
- (void)deleteFBO;
- (void)updateFBO;
- (void)makeCurrentFBO;
- (void)swapFBO;
- (void)flushFBO;
- (void)finishFBO;
- (void)bindFBO;
- (void)renderFBOToView;
- (void)clearVisibleRegions;
@end
/* Helper view. This view is added as a sub view of the parent view to track
* main window changes. Whenever the main window is changed (which happens on
* fullscreen/seamless entry/exit) the overlay window is informed & can add
* them self as a child window again. */
@class OverlayWindow;
@interface OverlayHelperView: NSView
{
@private
}
@end
/* Custom window class. This is the overlay window which contains our custom
* NSView. Its a direct child of the Qt Main window. It marks its background
* transparent & non opaque to make clipping possible. It also disable mouse
* events and handle frame change events of the parent view. */
@interface OverlayWindow: NSWindow
{
@private
}
@end
/********************************************************************************
*
* OverlayOpenGLContext class implementation
*
********************************************************************************/
{
if (self)
return self;
}
- (void)dealloc
{
[super dealloc];
}
{
#else
}
{
return m_pView;
#else
return [super view];
}
-(void)clearDrawable
{
[super clearDrawable];
}
{
return m_pPixelFormat;
}
@end;
/********************************************************************************
*
* OverlayHelperView class implementation
*
********************************************************************************/
{
return self;
}
-(void)viewDidMoveToWindow
{
}
@end
/********************************************************************************
*
* OverlayWindow class implementation
*
********************************************************************************/
{
if(self = [super initWithContentRect:NSZeroRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO])
{
/* Add the helper view as a child of the parent view to get notifications */
/* Make sure this window is transparent */
/* For debugging */
#else
/* Disable mouse events for this window */
/* Set the overlay view as out content view */
/* Add ourself as a child to the parent views window */
/* Ask to get notifications when our parent window frame changes. */
}
return self;
}
- (void)dealloc
{
[super dealloc];
}
{
/* Reposition this window with the help of the OverlayView */
}
{
if(pWindow)
{
/* Ask to get notifications when our parent window frame changes. */
/* Add us self as child window */
/* Reshape the overlay view after a short waiting time to let the main
* window resize itself properly. */
}
}
@end
/********************************************************************************
*
* OverlayView class implementation
*
********************************************************************************/
{
/* Make some reasonable defaults */
m_FBOId = 0;
m_FBOTexId = 0;
m_FBODepthId = 0;
m_FBOStencilId = 0;
m_cClipRects = 0;
m_Pos = NSZeroPoint;
m_Size = NSZeroSize;
return self;
}
- (void)dealloc
{
if (m_pGLCtx)
{
}
if (m_pSharedGLCtx)
{
}
[super dealloc];
}
{
// NSGraphicsContext*pC = [NSGraphicsContext currentContext];
// [[NSColor blueColor] set];
// NSBezierPath *p = [[NSBezierPath alloc] bezierPathWithOvalInRect:[self frame]];
// [p fill];
// [[NSColor greenColor] set];
// [p stroke];
// if ([self lockFocusIfCanDraw])
// {
// [self renderFBOToView];
// [self unlockFocus];
// }
}
{
}
- (NSOpenGLContext*)glCtx
{
return m_pGLCtx;
}
{
}
{
return m_Pos;
}
{
}
{
return m_Size;
}
- (void)reshape
{
/* Getting the right screen coordinates of the parents frame is a little bit
* complicated. */
NSPoint parentPos = [[m_pParentView window] convertBaseToScreen:[[m_pParentView superview] convertPointToBase:NSMakePoint(parentFrame.origin.x, parentFrame.origin.y + parentFrame.size.height)]];
/* Calculate the new screen coordinates of the overlay window. */
childPos = [[m_pParentView window] convertBaseToScreen:[[m_pParentView superview] convertPointToBase:childPos]];
/* Make a frame out of it. */
/* We have to make sure that the overlay window will not be displayed out
* of the parent window. So intersect both frames & use the result as the new
* frame for the window. */
/* Later we have to correct the texture position in the case the window is
* out of the parents window frame. So save the shift values for later use. */
else
m_RootShift.x = 0;
else
m_RootShift.y = 0;
// NSScrollView *pScrollView = [[[m_pParentView window] contentView] enclosingScrollView];
// if (pScrollView)
// {
// NSRect scrollRect = [pScrollView documentVisibleRect];
// NSRect scrollRect = [m_pParentView visibleRect];
// printf ("sc rect: %d %d %d %d\n", (int) scrollRect.origin.x,(int) scrollRect.origin.y,(int) scrollRect.size.width,(int) scrollRect.size.height);
// NSRect b = [[m_pParentView superview] bounds];
// printf ("bound rect: %d %d %d %d\n", (int) b.origin.x,(int) b.origin.y,(int) b.size.width,(int) b.size.height);
// newFrame.origin.x += scrollRect.origin.x;
// newFrame.origin.y += scrollRect.origin.y;
// }
/* Set the new frame. */
}
- (void)createFBO
{
/* If not previously setup generate IDs for FBO and its associated texture. */
if (!m_FBOId)
{
/* Make sure the framebuffer extension is supported */
/* Get the extension name string. It is a space-delimited list of the
* OpenGL extensions that are supported by the current renderer. */
if (!isFBO)
{
DEBUG_MSG(("Your system does not support framebuffer extension\n"));
}
/* Create FBO object */
// glGenRenderbuffersEXT(1, &m_FBODepthId);
// glGenRenderbuffersEXT(1, &m_FBOStencilId);
}
/* Bind to FBO */
/* Sanity check against maximum OpenGL texture size. If bigger adjust to
* maximum possible size while maintain the aspect ratio. */
// maxTexSize = 150;
{
if (imageAspectRatio > 1)
{
}
else
{
}
}
/* Initialize FBO Texture */
/* The GPUs like the GL_BGRA / GL_UNSIGNED_INT_8_8_8_8_REV combination
* others are also valid, but might incur a costly software translation. */
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);
/* Now attach texture to the FBO as its color destination */
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, m_FBOTexId, 0);
// glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_STENCIL_EXT, m_FBOTexSize.width, m_FBOTexSize.height);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_FBODepthStencilPackedId);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_FBODepthStencilPackedId);
// glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_FBODepthId);
// 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);
// glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, m_FBODepthId, 0);
//
// glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_FBOStencilId);
// 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);
// glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, m_FBOStencilId, 0);
/* Initialize Depth Render Buffer */
// glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_FBODepthId);
// glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, r.size.width, r.size.height);
/* and attach it to the FBO */
// glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_FBODepthId);
//
// glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_FBOStencilId);
// glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX, r.size.width, r.size.height);
// glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_FBOStencilId);
// glClearColor (clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
// glClearColor (0, 0, 0, 0);
// glClear(GL_COLOR_BUFFER_BIT);
/* Make sure the FBO was created succesfully. */
DEBUG_MSG(("Framebuffer Object creation or update failed!\n"));
/* Initialize with one big visual region over the full size */
m_cClipRects = 1;
}
- (void)deleteFBO
{
{
if (m_FBODepthId > 0)
{
m_FBODepthId = 0;
}
if (m_FBOStencilId > 0)
{
m_FBOStencilId = 0;
}
if (m_FBODepthStencilPackedId > 0)
{
}
if (m_FBOTexId > 0)
{
m_FBOTexId = 0;
}
if (m_FBOId > 0)
{
m_FBOId = 0;
}
}
}
- (void)updateFBO
{
if (m_pGLCtx)
{
}
}
- (void)makeCurrentFBO
{
if (m_pGLCtx)
{
{
/* We change the active view, so flush first */
glFlush();
}
// if ([NSOpenGLContext currentContext] != m_pGLCtx)
{
// [m_pGLCtx update];
}
}
}
- (void)swapFBO
{
// glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
if ([self lockFocusIfCanDraw])
{
[self unlockFocus];
}
// glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FBOId);
#else
}
- (void)flushFBO
{
glFlush();
// glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
if ([self lockFocusIfCanDraw])
{
[self unlockFocus];
}
// glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FBOId);
}
- (void)finishFBO
{
glFinish();
// glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
if ([self lockFocusIfCanDraw])
{
[self unlockFocus];
}
// glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FBOId);
}
- (void)bindFBO
{
}
- (void)renderFBOToView
{
if (!m_pSharedGLCtx)
{
/* Create a shared context out of the main context. Use the same pixel format. */
m_pSharedGLCtx = [[NSOpenGLContext alloc] initWithFormat:[(OverlayOpenGLContext*)m_pGLCtx openGLPixelFormat] shareContext:m_pGLCtx];
/* Set the new context as non opaque */
/* Only swap on screen refresh */
// GLint swap = 1;
// [m_pSharedGLCtx setValues:&swap forParameter:NSOpenGLCPSwapInterval];
/* Set this view as the drawable for the new context */
}
if (m_pSharedGLCtx)
{
if (m_FBOTexId > 0)
{
// printf ("renderFBOToView\n");
// CGLLockContext([m_pGLCtx CGLContextObj]);
/* Setup all matrices */
/* Clear background to transparent */
GLint i;
for (i = 0; i < m_cClipRects; ++i)
{
{
}
glEnd();
}
// CGLUnlockContext([m_pGLCtx CGLContextObj]);
}
}
}
- (void)clearVisibleRegions
{
if(m_paClipRects)
{
}
m_cClipRects = 0;
}
{
DEBUG_MSG_1(("New region recieved\n"));
if (cRects>0)
{
}
}
@end
/********************************************************************************
*
* OpenGL context management
*
********************************************************************************/
{
{
};
int i = 4;
if (fVisParams & CR_ALPHA_BIT)
{
DEBUG_MSG(("CR_ALPHA_BIT requested\n"));
attribs[i++] = NSOpenGLPFAAlphaSize;
attribs[i++] = 8;
}
if (fVisParams & CR_DEPTH_BIT)
{
DEBUG_MSG(("CR_DEPTH_BIT requested\n"));
attribs[i++] = NSOpenGLPFADepthSize;
attribs[i++] = 24;
}
if (fVisParams & CR_STENCIL_BIT)
{
DEBUG_MSG(("CR_STENCIL_BIT requested\n"));
attribs[i++] = NSOpenGLPFAStencilSize;
attribs[i++] = 8;
}
if (fVisParams & CR_ACCUM_BIT)
{
DEBUG_MSG(("CR_ACCUM_BIT requested\n"));
attribs[i++] = NSOpenGLPFAAccumSize;
if (fVisParams & CR_ALPHA_BIT)
attribs[i++] = 32;
else
attribs[i++] = 24;
}
if (fVisParams & CR_MULTISAMPLE_BIT)
{
DEBUG_MSG(("CR_MULTISAMPLE_BIT requested\n"));
attribs[i++] = NSOpenGLPFASampleBuffers;
attribs[i++] = 1;
attribs[i++] = NSOpenGLPFASamples;
attribs[i++] = 4;
}
if (fVisParams & CR_DOUBLE_BIT)
{
DEBUG_MSG(("CR_DOUBLE_BIT requested\n"));
attribs[i++] = NSOpenGLPFADoubleBuffer;
}
if (fVisParams & CR_STEREO_BIT)
{
DEBUG_MSG(("CR_DOUBLE_BIT requested\n"));
attribs[i++] = NSOpenGLPFAStereo;
}
/* Mark the end */
attribs[i++] = 0;
/* Choose a pixel format */
if (pFmt)
{
/* Enable multi threaded OpenGL engine */
// CGLContextObj cglCtx = [*ppCtx CGLContextObj];
// CGLError err = CGLEnable(cglCtx, kCGLCEMPEngine);
// if (err != kCGLNoError)
// printf ("Couldn't enable MT OpenGL engine!\n");
}
}
{
// [pCtx release];
}
/********************************************************************************
*
* View management
*
********************************************************************************/
{
/* Create our worker view */
OverlayView* pView = [[OverlayView alloc] initWithFrame:NSZeroRect thread:RTThreadSelf() parentView:pParentView];
if (pView)
{
/* We need a real window as container for the view */
/* Return the freshly created overlay view */
}
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
/********************************************************************************
*
* Additional OpenGL wrapper
*
********************************************************************************/
void cocoaFlush()
{
// glFlush();
// return;
DEBUG_MSG_1(("glFlush called\n"));
if (pCtx)
{
if (pView)
{
}
}
#else
glFlush();
}
void cocoaFinish()
{
DEBUG_MSG_1(("glFinish called\n"));
if (pCtx)
{
if (pView)
{
}
}
#else
glFinish();
}
{
if (framebuffer != 0)
else
{
if (pCtx)
{
if (pView)
{
}
}
}
#else
}