aboutsummaryrefslogtreecommitdiffstats
path: root/code/macosx/macosx_glsmp_ports.m
diff options
context:
space:
mode:
Diffstat (limited to 'code/macosx/macosx_glsmp_ports.m')
-rwxr-xr-xcode/macosx/macosx_glsmp_ports.m850
1 files changed, 425 insertions, 425 deletions
diff --git a/code/macosx/macosx_glsmp_ports.m b/code/macosx/macosx_glsmp_ports.m
index ce6dc9f..8f39a4e 100755
--- a/code/macosx/macosx_glsmp_ports.m
+++ b/code/macosx/macosx_glsmp_ports.m
@@ -1,425 +1,425 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code is free software; you can redistribute it
-and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-Quake III Arena source code is distributed in the hope that it will be
-useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-#import "macosx_glimp.h"
-
-#include "tr_local.h"
-#import "macosx_local.h"
-#import "macosx_display.h"
-
-#import <AppKit/AppKit.h>
-#import <Foundation/Foundation.h>
-#import <mach/mach.h>
-#import <mach/mach_error.h>
-
-
-#warning Using Mach Ports SMP acceleration implementation
-
-/*
-===========================================================
-
-SMP acceleration
-
-===========================================================
-*/
-
-#import <pthread.h>
-
-#define USE_MACH_PORTS 1
-
-// This is a small cover layer that makes for easier calling
-
-typedef struct _MsgPort {
-#if USE_MACH_PORTS
- mach_port_t port;
- id nsPort;
-#else
- pthread_mutex_t mutex;
- pthread_cond_t condition;
- volatile unsigned int status;
- unsigned int msgCode;
- void *msgData;
-#endif
-} MsgPort;
-
-static BOOL portsInited = NO;
-static pthread_mutex_t logMutex;
-
-static unsigned int renderMsgOutstanding;
-static unsigned int rendererProcessingCommand;
-
-static MsgPort rendererMsgPort;
-static MsgPort frontEndMsgPort;
-
-enum {
- MsgNone,
- MsgPending,
-};
-
-enum {
- MsgCodeInvalid = 0,
- RenderCommandMsg = 1,
- RenderCompletedMsg = 2,
-};
-
-static /*inline*/ void MsgPortInit(MsgPort *port)
-{
-#if USE_MACH_PORTS
- port->nsPort = [[NSMachPort alloc] init];
- port->port = [port->nsPort machPort];
-
- //rc = mach_port_allocate(mach_task_self(), MACH_PORT_TYPE_SEND_RECEIVE, &port->port);
- //if (rc) {
- // fprintf(stderr, "MsgPortInit: mach_port_allocate returned: %d: %s \n",rc, mach_error_string(rc));
- // }
-#else
- int rc;
- rc = pthread_mutex_init(&port->mutex, NULL);
- if (rc) {
- ri.Printf(PRINT_ALL, "MsgPortInit: pthread_mutex_init returned: %d: %s\n", rc, strerror(rc));
- }
- rc = pthread_cond_init(&port->condition, NULL);
- if (rc) {
- ri.Printf(PRINT_ALL, "EventInit: pthread_cond_init returned %d: %s\n", rc, strerror(rc));
- }
- port->status = MsgNone;
- port->msgCode = MsgCodeInvalid;
- port->msgData = NULL;
-#endif
-}
-
-static /*inline*/ void _SendMsg(MsgPort *port, unsigned int msgCode, void *msgData,
- const char *functionName, const char *portName, const char *msgName)
-{
- int rc;
-
-#if USE_MACH_PORTS
- mach_msg_header_t msg;
-
- //printf("SendMsg: %s %s %s (%d %08lx)\n",functionName, portName, msgName, msgCode, msgData);
-/*
- typedef struct
- {
- mach_msg_bits_t msgh_bits;
- mach_msg_size_t msgh_size;
- mach_port_t msgh_remote_port;
- mach_port_t msgh_local_port;
- mach_msg_size_t msgh_reserved;
- mach_msg_id_t msgh_id;
- } mach_msg_header_t;
-*/
- msg.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,MACH_MSG_TYPE_MAKE_SEND_ONCE);
- msg.msgh_size=sizeof(msg);
- //msg.msg_type=MSG_TYPE_NORMAL;
- msg.msgh_local_port=MACH_PORT_NULL;
- msg.msgh_remote_port=port->port;
- msg.msgh_reserved = 0;
- msg.msgh_id=(mach_msg_id_t)msgData; // HACK
-
- rc = mach_msg_send(&msg);
- if(rc) {
- fprintf(stderr,"SendMsg: mach_msg_send returned %d: %s\n", rc, mach_error_string(rc));
- }
-#else
- //printf("SendMsg: %s %s %s (%d %08lx)\n",functionName, portName, msgName, msgCode, msgData);
- rc = pthread_mutex_lock(&port->mutex);
- if(rc) {
- fprintf(stderr,"SendMsg: pthread_mutex_lock returned %d: %s\n", rc, strerror(rc));
- }
-
- /* Block until port is empty */
- while(port->status != MsgNone) {
- //fprintf(stderr, "SendMsg: %s blocking until port %s is empty\n", functionName, portName);
- rc = pthread_cond_wait(&port->condition, &port->mutex);
- if(rc) {
- fprintf(stderr, "SendMsg: pthread_cond_wait returned %d: %s\n", rc, strerror(rc));
- }
- }
-
- /* Queue msg */
- port->msgCode = msgCode;
- port->msgData = msgData;
- port->status = MsgPending;
-
- /* Unlock port */
- rc = pthread_mutex_unlock(&port->mutex);
- if(rc) {
- fprintf(stderr, "SendMsg: pthread_mutex_unlock returned %d: %s\n", rc, strerror(rc));
- }
-
- /* Wake up any threads blocked waiting for a message */
- rc = pthread_cond_broadcast(&port->condition);
- if(rc) {
- fprintf(stderr, "SendMsg: pthread_cond_broadcast returned %d: %s\n", rc, strerror(rc));
- }
-#endif
-}
-
-static /*inline*/ void _WaitMsg(MsgPort *port, unsigned int *msgCode, void **msgData,
- const char *functionName, const char *portName)
-{
- int rc;
-#if USE_MACH_PORTS
- mach_msg_empty_rcv_t msg;
-
- //printf("WaitMsg: %s %s\n",functionName, portName);
-
- msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,MACH_MSG_TYPE_MAKE_SEND_ONCE);
- msg.header.msgh_size= sizeof(msg);
- //msg.msg_type=MSG_TYPE_NORMAL;
- msg.header.msgh_local_port=port->port;
- msg.header.msgh_remote_port=MACH_PORT_NULL;
- msg.header.msgh_reserved = 0;
- msg.header.msgh_id=(mach_msg_id_t)msgData; // HACK
-
- rc = mach_msg_receive(&msg.header);
- if(rc) {
- fprintf(stderr,"SendMsg: mach_msg_receive returned %d: %s\n", rc, mach_error_string(rc));
- }
-
- *msgData = (void *)msg.header.msgh_id;
- //printf("WaitMsg: %s %s got %08lx\n",functionName, portName, *msgData);
-#else
- //printf("WaitMsg: %s %s\n",functionName, portName);
-
- rc = pthread_mutex_lock(&port->mutex);
- if(rc) {
- fprintf(stderr, "WaitMsg: pthread_mutex_lock returned %d: %s\n", rc, strerror(rc));
- }
-
- /* Block until port is empty */
- while(port->status != MsgPending) {
- rc = pthread_cond_wait(&port->condition, &port->mutex);
- if(rc) {
- fprintf(stderr, "WaitMsg: pthread_cond_wait returned %d: %s\n", rc, strerror(rc));
- }
- }
-
- /* Remove msg */
- *msgCode = port->msgCode;
- *msgData = port->msgData;
-
- //printf("WaitMsg: %s %s got %d %08lx\n",functionName, portName, *msgCode, *msgData);
-
- port->status = MsgNone;
- port->msgCode = 0;
- port->msgData = NULL;
-
- rc = pthread_mutex_unlock(&port->mutex);
- if(rc) {
- fprintf(stderr, "WaitMsg: pthread_mutex_unlock returned %d: %s\n", rc, strerror(rc));
- }
-
- /* Wake up any threads blocked waiting for port to be empty. */
- rc = pthread_cond_broadcast(&port->condition);
- if(rc) {
- fprintf(stderr, "SendMsg: pthread_cond_broadcast returned %d: %s\n", rc, strerror(rc));
- }
-#endif
-}
-
-
-#define SendMsg(p, c, d) _SendMsg(p, c, d, __PRETTY_FUNCTION__, #p, #c)
-#define WaitMsg(p, c, d) _WaitMsg(p, c, d, __PRETTY_FUNCTION__, #p)
-
-#if 0
-static void _Log(const char *msg)
-{
- int rc;
-
- rc = pthread_mutex_lock(&logMutex);
- if (rc)
- ri.Printf(PRINT_ALL, "_Log: pthread_mutex_lock returned %d: %s\n", rc, strerror(rc));
-
- fputs(msg,stderr);
- fflush(stderr);
-
- rc = pthread_mutex_unlock(&logMutex);
- if (rc)
- ri.Printf(PRINT_ALL, "_Log: pthread_mutex_unlock returned %d: %s\n", rc, strerror(rc));
-}
-#endif
-
-
-//
-// The main Q3 SMP API
-//
-
-static void (*glimpRenderThread)( void ) = NULL;
-
-static void *GLimp_RenderThreadWrapper(void *arg)
-{
- Com_Printf("Render thread starting\n");
-
- glimpRenderThread();
-
-#ifndef USE_CGLMACROS
- // Unbind the context before we die
- OSX_GLContextClearCurrent();
-#endif
-
- // Send one last message back to front end before we die...
- // This is somewhat of a hack.. fixme.
- if (rendererProcessingCommand) {
- SendMsg(&frontEndMsgPort, RenderCompletedMsg, NULL);
- rendererProcessingCommand = NO;
- }
-
- Com_Printf("Render thread terminating\n");
-
- return arg;
-}
-
-qboolean GLimp_SpawnRenderThread( void (*function)( void ) )
-{
- pthread_t renderThread;
- int rc;
-
- if (!portsInited) {
- portsInited = YES;
- MsgPortInit(&rendererMsgPort);
- MsgPortInit(&frontEndMsgPort);
- renderMsgOutstanding = NO;
- rendererProcessingCommand = NO;
- pthread_mutex_init(&logMutex, NULL);
- }
-
- glimpRenderThread = function;
-
- rc = pthread_create(&renderThread,
- NULL, // attributes
- GLimp_RenderThreadWrapper,
- NULL); // argument
- if (rc) {
- ri.Printf(PRINT_ALL, "pthread_create returned %d: %s", rc, strerror(rc));
- return qfalse;
- } else {
- rc = pthread_detach(renderThread);
- if (rc) {
- ri.Printf(PRINT_ALL, "pthread_detach returned %d: %s", rc, strerror(rc));
- }
- }
-
- return qtrue;
-}
-
-static volatile void *smpData;
-
-// TJW - This is calling in the rendering thread to wait until another
-// command buffer is ready. The command buffer returned might be NULL,
-// indicating that the rendering thread should exit.
-void *GLimp_RendererSleep(void)
-{
- //_Log(__PRETTY_FUNCTION__ " entered");
- unsigned int msgCode;
- void *msgData;
-
- GLSTAMP("GLimp_RendererSleep start", 0);
-
-#ifndef USE_CGLMACROS
- // Clear the current context while we sleep so the main thread can access it
- OSX_GLContextClearCurrent();
-#endif
-
- // Let the main thread we are idle and that no work is queued
- //_Log("rs0\n");
- /* If we actually had some work to do, then tell the front end we completed it. */
- if (rendererProcessingCommand) {
- SendMsg(&frontEndMsgPort, RenderCompletedMsg, NULL);
- rendererProcessingCommand = NO;
- }
-
- // Wait for new msg
- for (;;) {
- WaitMsg(&rendererMsgPort, &msgCode, &msgData);
- if (1 || msgCode == RenderCommandMsg) {
- smpData = msgData;
- break;
- } else {
- printf("renderer received unknown message: %d\n",msgCode);
- }
- }
-
-#ifndef USE_CGLMACROS
- // We are going to render a frame... retake the context
- OSX_GLContextSetCurrent();
-#endif
-
- rendererProcessingCommand = YES;
-
- GLSTAMP("GLimp_RendererSleep end", 0);
-
- return (void *)smpData;
-}
-
-
-// TJW - This is from the main thread to wait until the rendering thread
-// has completed the command buffer that it has
-void GLimp_FrontEndSleep(void)
-{
- unsigned int msgCode;
- void *msgData;
-
- GLSTAMP("GLimp_FrontEndSleep start", 1);
-
- if (renderMsgOutstanding) {
- for (;;) {
- WaitMsg(&frontEndMsgPort, &msgCode, &msgData);
- if(1 || msgCode == RenderCompletedMsg) {
- break;
- } else {
- printf("front end received unknown message: %d\n",msgCode);
- }
- }
- renderMsgOutstanding = NO;
- }
-
-#ifndef USE_CGLMACROS
- // We are done waiting for the background thread, take the current context back.
- OSX_GLContextSetCurrent();
-#endif
-
- GLSTAMP("GLimp_FrontEndSleep end", 1);
-}
-
-
-// TJW - This is called in the main thread to issue another command
-// buffer to the rendering thread. This is always called AFTER
-// GLimp_FrontEndSleep, so we know that there is no command
-// pending in 'smpData'.
-void GLimp_WakeRenderer( void *data )
-{
- GLSTAMP("GLimp_WakeRenderer start", 1);
-
-#ifndef USE_CGLMACROS
- // We want the background thread to draw stuff. Give up the current context
- OSX_GLContextClearCurrent();
-#endif
-
- SendMsg(&rendererMsgPort, RenderCommandMsg, data);
-
- // Don't set flag saying that the renderer is processing something if it's just
- // being told to exit.
- //if(data != NULL)
- renderMsgOutstanding = YES;
-
- GLSTAMP("GLimp_WakeRenderer end", 1);
-}
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+#import "macosx_glimp.h"
+
+#include "tr_local.h"
+#import "macosx_local.h"
+#import "macosx_display.h"
+
+#import <AppKit/AppKit.h>
+#import <Foundation/Foundation.h>
+#import <mach/mach.h>
+#import <mach/mach_error.h>
+
+
+#warning Using Mach Ports SMP acceleration implementation
+
+/*
+===========================================================
+
+SMP acceleration
+
+===========================================================
+*/
+
+#import <pthread.h>
+
+#define USE_MACH_PORTS 1
+
+// This is a small cover layer that makes for easier calling
+
+typedef struct _MsgPort {
+#if USE_MACH_PORTS
+ mach_port_t port;
+ id nsPort;
+#else
+ pthread_mutex_t mutex;
+ pthread_cond_t condition;
+ volatile unsigned int status;
+ unsigned int msgCode;
+ void *msgData;
+#endif
+} MsgPort;
+
+static BOOL portsInited = NO;
+static pthread_mutex_t logMutex;
+
+static unsigned int renderMsgOutstanding;
+static unsigned int rendererProcessingCommand;
+
+static MsgPort rendererMsgPort;
+static MsgPort frontEndMsgPort;
+
+enum {
+ MsgNone,
+ MsgPending,
+};
+
+enum {
+ MsgCodeInvalid = 0,
+ RenderCommandMsg = 1,
+ RenderCompletedMsg = 2,
+};
+
+static /*inline*/ void MsgPortInit(MsgPort *port)
+{
+#if USE_MACH_PORTS
+ port->nsPort = [[NSMachPort alloc] init];
+ port->port = [port->nsPort machPort];
+
+ //rc = mach_port_allocate(mach_task_self(), MACH_PORT_TYPE_SEND_RECEIVE, &port->port);
+ //if (rc) {
+ // fprintf(stderr, "MsgPortInit: mach_port_allocate returned: %d: %s \n",rc, mach_error_string(rc));
+ // }
+#else
+ int rc;
+ rc = pthread_mutex_init(&port->mutex, NULL);
+ if (rc) {
+ ri.Printf(PRINT_ALL, "MsgPortInit: pthread_mutex_init returned: %d: %s\n", rc, strerror(rc));
+ }
+ rc = pthread_cond_init(&port->condition, NULL);
+ if (rc) {
+ ri.Printf(PRINT_ALL, "EventInit: pthread_cond_init returned %d: %s\n", rc, strerror(rc));
+ }
+ port->status = MsgNone;
+ port->msgCode = MsgCodeInvalid;
+ port->msgData = NULL;
+#endif
+}
+
+static /*inline*/ void _SendMsg(MsgPort *port, unsigned int msgCode, void *msgData,
+ const char *functionName, const char *portName, const char *msgName)
+{
+ int rc;
+
+#if USE_MACH_PORTS
+ mach_msg_header_t msg;
+
+ //printf("SendMsg: %s %s %s (%d %08lx)\n",functionName, portName, msgName, msgCode, msgData);
+/*
+ typedef struct
+ {
+ mach_msg_bits_t msgh_bits;
+ mach_msg_size_t msgh_size;
+ mach_port_t msgh_remote_port;
+ mach_port_t msgh_local_port;
+ mach_msg_size_t msgh_reserved;
+ mach_msg_id_t msgh_id;
+ } mach_msg_header_t;
+*/
+ msg.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,MACH_MSG_TYPE_MAKE_SEND_ONCE);
+ msg.msgh_size=sizeof(msg);
+ //msg.msg_type=MSG_TYPE_NORMAL;
+ msg.msgh_local_port=MACH_PORT_NULL;
+ msg.msgh_remote_port=port->port;
+ msg.msgh_reserved = 0;
+ msg.msgh_id=(mach_msg_id_t)msgData; // HACK
+
+ rc = mach_msg_send(&msg);
+ if(rc) {
+ fprintf(stderr,"SendMsg: mach_msg_send returned %d: %s\n", rc, mach_error_string(rc));
+ }
+#else
+ //printf("SendMsg: %s %s %s (%d %08lx)\n",functionName, portName, msgName, msgCode, msgData);
+ rc = pthread_mutex_lock(&port->mutex);
+ if(rc) {
+ fprintf(stderr,"SendMsg: pthread_mutex_lock returned %d: %s\n", rc, strerror(rc));
+ }
+
+ /* Block until port is empty */
+ while(port->status != MsgNone) {
+ //fprintf(stderr, "SendMsg: %s blocking until port %s is empty\n", functionName, portName);
+ rc = pthread_cond_wait(&port->condition, &port->mutex);
+ if(rc) {
+ fprintf(stderr, "SendMsg: pthread_cond_wait returned %d: %s\n", rc, strerror(rc));
+ }
+ }
+
+ /* Queue msg */
+ port->msgCode = msgCode;
+ port->msgData = msgData;
+ port->status = MsgPending;
+
+ /* Unlock port */
+ rc = pthread_mutex_unlock(&port->mutex);
+ if(rc) {
+ fprintf(stderr, "SendMsg: pthread_mutex_unlock returned %d: %s\n", rc, strerror(rc));
+ }
+
+ /* Wake up any threads blocked waiting for a message */
+ rc = pthread_cond_broadcast(&port->condition);
+ if(rc) {
+ fprintf(stderr, "SendMsg: pthread_cond_broadcast returned %d: %s\n", rc, strerror(rc));
+ }
+#endif
+}
+
+static /*inline*/ void _WaitMsg(MsgPort *port, unsigned int *msgCode, void **msgData,
+ const char *functionName, const char *portName)
+{
+ int rc;
+#if USE_MACH_PORTS
+ mach_msg_empty_rcv_t msg;
+
+ //printf("WaitMsg: %s %s\n",functionName, portName);
+
+ msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,MACH_MSG_TYPE_MAKE_SEND_ONCE);
+ msg.header.msgh_size= sizeof(msg);
+ //msg.msg_type=MSG_TYPE_NORMAL;
+ msg.header.msgh_local_port=port->port;
+ msg.header.msgh_remote_port=MACH_PORT_NULL;
+ msg.header.msgh_reserved = 0;
+ msg.header.msgh_id=(mach_msg_id_t)msgData; // HACK
+
+ rc = mach_msg_receive(&msg.header);
+ if(rc) {
+ fprintf(stderr,"SendMsg: mach_msg_receive returned %d: %s\n", rc, mach_error_string(rc));
+ }
+
+ *msgData = (void *)msg.header.msgh_id;
+ //printf("WaitMsg: %s %s got %08lx\n",functionName, portName, *msgData);
+#else
+ //printf("WaitMsg: %s %s\n",functionName, portName);
+
+ rc = pthread_mutex_lock(&port->mutex);
+ if(rc) {
+ fprintf(stderr, "WaitMsg: pthread_mutex_lock returned %d: %s\n", rc, strerror(rc));
+ }
+
+ /* Block until port is empty */
+ while(port->status != MsgPending) {
+ rc = pthread_cond_wait(&port->condition, &port->mutex);
+ if(rc) {
+ fprintf(stderr, "WaitMsg: pthread_cond_wait returned %d: %s\n", rc, strerror(rc));
+ }
+ }
+
+ /* Remove msg */
+ *msgCode = port->msgCode;
+ *msgData = port->msgData;
+
+ //printf("WaitMsg: %s %s got %d %08lx\n",functionName, portName, *msgCode, *msgData);
+
+ port->status = MsgNone;
+ port->msgCode = 0;
+ port->msgData = NULL;
+
+ rc = pthread_mutex_unlock(&port->mutex);
+ if(rc) {
+ fprintf(stderr, "WaitMsg: pthread_mutex_unlock returned %d: %s\n", rc, strerror(rc));
+ }
+
+ /* Wake up any threads blocked waiting for port to be empty. */
+ rc = pthread_cond_broadcast(&port->condition);
+ if(rc) {
+ fprintf(stderr, "SendMsg: pthread_cond_broadcast returned %d: %s\n", rc, strerror(rc));
+ }
+#endif
+}
+
+
+#define SendMsg(p, c, d) _SendMsg(p, c, d, __PRETTY_FUNCTION__, #p, #c)
+#define WaitMsg(p, c, d) _WaitMsg(p, c, d, __PRETTY_FUNCTION__, #p)
+
+#if 0
+static void _Log(const char *msg)
+{
+ int rc;
+
+ rc = pthread_mutex_lock(&logMutex);
+ if (rc)
+ ri.Printf(PRINT_ALL, "_Log: pthread_mutex_lock returned %d: %s\n", rc, strerror(rc));
+
+ fputs(msg,stderr);
+ fflush(stderr);
+
+ rc = pthread_mutex_unlock(&logMutex);
+ if (rc)
+ ri.Printf(PRINT_ALL, "_Log: pthread_mutex_unlock returned %d: %s\n", rc, strerror(rc));
+}
+#endif
+
+
+//
+// The main Q3 SMP API
+//
+
+static void (*glimpRenderThread)( void ) = NULL;
+
+static void *GLimp_RenderThreadWrapper(void *arg)
+{
+ Com_Printf("Render thread starting\n");
+
+ glimpRenderThread();
+
+#ifndef USE_CGLMACROS
+ // Unbind the context before we die
+ OSX_GLContextClearCurrent();
+#endif
+
+ // Send one last message back to front end before we die...
+ // This is somewhat of a hack.. fixme.
+ if (rendererProcessingCommand) {
+ SendMsg(&frontEndMsgPort, RenderCompletedMsg, NULL);
+ rendererProcessingCommand = NO;
+ }
+
+ Com_Printf("Render thread terminating\n");
+
+ return arg;
+}
+
+qboolean GLimp_SpawnRenderThread( void (*function)( void ) )
+{
+ pthread_t renderThread;
+ int rc;
+
+ if (!portsInited) {
+ portsInited = YES;
+ MsgPortInit(&rendererMsgPort);
+ MsgPortInit(&frontEndMsgPort);
+ renderMsgOutstanding = NO;
+ rendererProcessingCommand = NO;
+ pthread_mutex_init(&logMutex, NULL);
+ }
+
+ glimpRenderThread = function;
+
+ rc = pthread_create(&renderThread,
+ NULL, // attributes
+ GLimp_RenderThreadWrapper,
+ NULL); // argument
+ if (rc) {
+ ri.Printf(PRINT_ALL, "pthread_create returned %d: %s", rc, strerror(rc));
+ return qfalse;
+ } else {
+ rc = pthread_detach(renderThread);
+ if (rc) {
+ ri.Printf(PRINT_ALL, "pthread_detach returned %d: %s", rc, strerror(rc));
+ }
+ }
+
+ return qtrue;
+}
+
+static volatile void *smpData;
+
+// TJW - This is calling in the rendering thread to wait until another
+// command buffer is ready. The command buffer returned might be NULL,
+// indicating that the rendering thread should exit.
+void *GLimp_RendererSleep(void)
+{
+ //_Log(__PRETTY_FUNCTION__ " entered");
+ unsigned int msgCode;
+ void *msgData;
+
+ GLSTAMP("GLimp_RendererSleep start", 0);
+
+#ifndef USE_CGLMACROS
+ // Clear the current context while we sleep so the main thread can access it
+ OSX_GLContextClearCurrent();
+#endif
+
+ // Let the main thread we are idle and that no work is queued
+ //_Log("rs0\n");
+ /* If we actually had some work to do, then tell the front end we completed it. */
+ if (rendererProcessingCommand) {
+ SendMsg(&frontEndMsgPort, RenderCompletedMsg, NULL);
+ rendererProcessingCommand = NO;
+ }
+
+ // Wait for new msg
+ for (;;) {
+ WaitMsg(&rendererMsgPort, &msgCode, &msgData);
+ if (1 || msgCode == RenderCommandMsg) {
+ smpData = msgData;
+ break;
+ } else {
+ printf("renderer received unknown message: %d\n",msgCode);
+ }
+ }
+
+#ifndef USE_CGLMACROS
+ // We are going to render a frame... retake the context
+ OSX_GLContextSetCurrent();
+#endif
+
+ rendererProcessingCommand = YES;
+
+ GLSTAMP("GLimp_RendererSleep end", 0);
+
+ return (void *)smpData;
+}
+
+
+// TJW - This is from the main thread to wait until the rendering thread
+// has completed the command buffer that it has
+void GLimp_FrontEndSleep(void)
+{
+ unsigned int msgCode;
+ void *msgData;
+
+ GLSTAMP("GLimp_FrontEndSleep start", 1);
+
+ if (renderMsgOutstanding) {
+ for (;;) {
+ WaitMsg(&frontEndMsgPort, &msgCode, &msgData);
+ if(1 || msgCode == RenderCompletedMsg) {
+ break;
+ } else {
+ printf("front end received unknown message: %d\n",msgCode);
+ }
+ }
+ renderMsgOutstanding = NO;
+ }
+
+#ifndef USE_CGLMACROS
+ // We are done waiting for the background thread, take the current context back.
+ OSX_GLContextSetCurrent();
+#endif
+
+ GLSTAMP("GLimp_FrontEndSleep end", 1);
+}
+
+
+// TJW - This is called in the main thread to issue another command
+// buffer to the rendering thread. This is always called AFTER
+// GLimp_FrontEndSleep, so we know that there is no command
+// pending in 'smpData'.
+void GLimp_WakeRenderer( void *data )
+{
+ GLSTAMP("GLimp_WakeRenderer start", 1);
+
+#ifndef USE_CGLMACROS
+ // We want the background thread to draw stuff. Give up the current context
+ OSX_GLContextClearCurrent();
+#endif
+
+ SendMsg(&rendererMsgPort, RenderCommandMsg, data);
+
+ // Don't set flag saying that the renderer is processing something if it's just
+ // being told to exit.
+ //if(data != NULL)
+ renderMsgOutstanding = YES;
+
+ GLSTAMP("GLimp_WakeRenderer end", 1);
+}