diff options
Diffstat (limited to 'code/macosx/macosx_glsmp_ports.m')
-rwxr-xr-x | code/macosx/macosx_glsmp_ports.m | 850 |
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); +} |