openmohaa/code/renderer_gl3/sdl_glimp.c

1705 lines
41 KiB
C
Raw Normal View History

2016-03-27 11:49:47 +02:00
/*
===========================================================================
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 Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#ifdef USE_LOCAL_HEADERS
# include "SDL.h"
#else
# include <SDL.h>
#endif
#if !SDL_VERSION_ATLEAST(1, 2, 10)
#define SDL_GL_ACCELERATED_VISUAL 15
#define SDL_GL_SWAP_CONTROL 16
#elif MINSDL_PATCH >= 10
#error Code block no longer necessary, please remove
#endif
#ifdef SMP
# include <SDL_thread.h>
# ifdef SDL_VIDEO_DRIVER_X11
# include <X11/Xlib.h>
# endif
#endif
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "tr_local.h"
#include "../client/client.h"
#include "../sys/sys_local.h"
#include "../sdl/sdl_icon.h"
#include "SDL_syswm.h"
#if defined(WIN32)
#include <GL/wglew.h>
#else
#include <GL/glxew.h>
#endif
/* Just hack it for now. */
#ifdef MACOS_X
#include <OpenGL/OpenGL.h>
typedef CGLContextObj QGLContext;
static QGLContext opengl_context;
static void GLimp_GetCurrentContext(void)
{
opengl_context = CGLGetCurrentContext();
}
#ifdef SMP
static void GLimp_SetCurrentContext(qboolean enable)
{
if(enable)
{
CGLSetCurrentContext(opengl_context);
}
else
{
CGLSetCurrentContext(NULL);
}
}
#endif
#elif SDL_VIDEO_DRIVER_X11
#include <GL/glx.h>
typedef struct
{
GLXContext ctx;
Display *dpy;
GLXDrawable drawable;
} QGLContext_t;
typedef QGLContext_t QGLContext;
static QGLContext opengl_context;
static void GLimp_GetCurrentContext(void)
{
opengl_context.ctx = glXGetCurrentContext();
opengl_context.dpy = glXGetCurrentDisplay();
opengl_context.drawable = glXGetCurrentDrawable();
}
#ifdef SMP
static void GLimp_SetCurrentContext(qboolean enable)
{
if(enable)
glXMakeCurrent(opengl_context.dpy, opengl_context.drawable, opengl_context.ctx);
else
glXMakeCurrent(opengl_context.dpy, None, NULL);
}
#endif
#elif _WIN32
typedef struct
{
HDC hDC; // handle to device context
HGLRC hGLRC; // handle to GL rendering context
} QGLContext_t;
typedef QGLContext_t QGLContext;
static QGLContext opengl_context;
static void GLimp_GetCurrentContext(void)
{
SDL_SysWMinfo info;
SDL_VERSION(&info.version);
if(!SDL_GetWMInfo(&info))
{
ri.Printf(PRINT_WARNING, "Failed to obtain HWND from SDL (InputRegistry)");
return;
}
opengl_context.hDC = GetDC(info.window);
opengl_context.hGLRC = info.hglrc;
}
#ifdef SMP
static void GLimp_SetCurrentContext(qboolean enable)
{
if(enable)
wglMakeCurrent(opengl_context.hDC, opengl_context.hGLRC);
else
wglMakeCurrent(opengl_context.hDC, NULL);
}
#endif
#else
static void GLimp_GetCurrentContext(void)
{
}
#ifdef SMP
static void GLimp_SetCurrentContext(qboolean enable)
{
}
#endif
#endif
#ifdef SMP
/*
===========================================================
SMP acceleration
===========================================================
*/
/*
* I have no idea if this will even work...most platforms don't offer
* thread-safe OpenGL libraries, and it looks like the original Linux
* code counted on each thread claiming the GL context with glXMakeCurrent(),
* which you can't currently do in SDL. We'll just have to hope for the best.
*/
static SDL_mutex *smpMutex = NULL;
static SDL_cond *renderCommandsEvent = NULL;
static SDL_cond *renderCompletedEvent = NULL;
static void (*renderThreadFunction) (void) = NULL;
static SDL_Thread *renderThread = NULL;
/*
===============
GLimp_RenderThreadWrapper
===============
*/
static int GLimp_RenderThreadWrapper(void *arg)
{
// These printfs cause race conditions which mess up the console output
Com_Printf("Render thread starting\n");
renderThreadFunction();
GLimp_SetCurrentContext(qfalse);
Com_Printf("Render thread terminating\n");
return 0;
}
/*
===============
GLimp_SpawnRenderThread
===============
*/
qboolean GLimp_SpawnRenderThread(void (*function) (void))
{
static qboolean warned = qfalse;
if(!warned)
{
Com_Printf("WARNING: You enable r_smp at your own risk!\n");
warned = qtrue;
}
#if !defined(MACOS_X) && !defined(WIN32) && !defined (SDL_VIDEO_DRIVER_X11)
return qfalse; /* better safe than sorry for now. */
#endif
if(renderThread != NULL) /* hopefully just a zombie at this point... */
{
Com_Printf("Already a render thread? Trying to clean it up...\n");
GLimp_ShutdownRenderThread();
}
smpMutex = SDL_CreateMutex();
if(smpMutex == NULL)
{
Com_Printf("smpMutex creation failed: %s\n", SDL_GetError());
GLimp_ShutdownRenderThread();
return qfalse;
}
renderCommandsEvent = SDL_CreateCond();
if(renderCommandsEvent == NULL)
{
Com_Printf("renderCommandsEvent creation failed: %s\n", SDL_GetError());
GLimp_ShutdownRenderThread();
return qfalse;
}
renderCompletedEvent = SDL_CreateCond();
if(renderCompletedEvent == NULL)
{
Com_Printf("renderCompletedEvent creation failed: %s\n", SDL_GetError());
GLimp_ShutdownRenderThread();
return qfalse;
}
renderThreadFunction = function;
renderThread = SDL_CreateThread(GLimp_RenderThreadWrapper, NULL);
if(renderThread == NULL)
{
ri.Printf(PRINT_ALL, "SDL_CreateThread() returned %s", SDL_GetError());
GLimp_ShutdownRenderThread();
return qfalse;
}
else
{
// tma 01/09/07: don't think this is necessary anyway?
//
// !!! FIXME: No detach API available in SDL!
//ret = pthread_detach( renderThread );
//if ( ret ) {
//ri.Printf( PRINT_ALL, "pthread_detach returned %d: %s", ret, strerror( ret ) );
//}
}
return qtrue;
}
/*
===============
GLimp_ShutdownRenderThread
===============
*/
void GLimp_ShutdownRenderThread(void)
{
if(renderThread != NULL)
{
SDL_WaitThread(renderThread, NULL);
renderThread = NULL;
}
if(smpMutex != NULL)
{
SDL_DestroyMutex(smpMutex);
smpMutex = NULL;
}
if(renderCommandsEvent != NULL)
{
SDL_DestroyCond(renderCommandsEvent);
renderCommandsEvent = NULL;
}
if(renderCompletedEvent != NULL)
{
SDL_DestroyCond(renderCompletedEvent);
renderCompletedEvent = NULL;
}
renderThreadFunction = NULL;
}
static volatile void *smpData = NULL;
static volatile qboolean smpDataReady;
/*
===============
GLimp_RendererSleep
===============
*/
void *GLimp_RendererSleep(void)
{
void *data = NULL;
GLimp_SetCurrentContext(qfalse);
SDL_LockMutex(smpMutex);
{
smpData = NULL;
smpDataReady = qfalse;
// after this, the front end can exit GLimp_FrontEndSleep
SDL_CondSignal(renderCompletedEvent);
while(!smpDataReady)
SDL_CondWait(renderCommandsEvent, smpMutex);
data = (void *)smpData;
}
SDL_UnlockMutex(smpMutex);
GLimp_SetCurrentContext(qtrue);
return data;
}
/*
===============
GLimp_FrontEndSleep
===============
*/
void GLimp_FrontEndSleep(void)
{
SDL_LockMutex(smpMutex);
{
while(smpData)
SDL_CondWait(renderCompletedEvent, smpMutex);
}
SDL_UnlockMutex(smpMutex);
GLimp_SetCurrentContext(qtrue);
}
/*
===============
GLimp_WakeRenderer
===============
*/
void GLimp_WakeRenderer(void *data)
{
GLimp_SetCurrentContext(qfalse);
SDL_LockMutex(smpMutex);
{
assert(smpData == NULL);
smpData = data;
smpDataReady = qtrue;
// after this, the renderer can continue through GLimp_RendererSleep
SDL_CondSignal(renderCommandsEvent);
}
SDL_UnlockMutex(smpMutex);
}
#else
// No SMP - stubs
void GLimp_RenderThreadWrapper(void *arg)
{
}
qboolean GLimp_SpawnRenderThread(void (*function) (void))
{
ri.Printf(PRINT_WARNING, "ERROR: SMP support was disabled at compile time\n");
return qfalse;
}
void GLimp_ShutdownRenderThread(void)
{
}
void *GLimp_RendererSleep(void)
{
return NULL;
}
void GLimp_FrontEndSleep(void)
{
}
void GLimp_WakeRenderer(void *data)
{
}
#endif
typedef enum
{
RSERR_OK,
RSERR_INVALID_FULLSCREEN,
RSERR_INVALID_MODE,
RSERR_UNKNOWN
} rserr_t;
static SDL_Surface *screen = NULL;
static const SDL_VideoInfo *videoInfo = NULL;
cvar_t *r_allowResize; // make window resizable
cvar_t *r_centerWindow;
cvar_t *r_sdlDriver;
/*
===============
GLimp_Shutdown
===============
*/
void GLimp_Shutdown(void)
{
ri.IN_Shutdown();
SDL_QuitSubSystem(SDL_INIT_VIDEO);
screen = NULL;
#if defined(SMP)
if(renderThread != NULL)
{
Com_Printf("Destroying renderer thread...\n");
GLimp_ShutdownRenderThread();
}
#endif
Com_Memset(&glConfig, 0, sizeof(glConfig));
Com_Memset(&glState, 0, sizeof(glState));
}
/*
===============
GLimp_CompareModes
===============
*/
static int GLimp_CompareModes(const void *a, const void *b)
{
const float ASPECT_EPSILON = 0.001f;
SDL_Rect *modeA = *(SDL_Rect **) a;
SDL_Rect *modeB = *(SDL_Rect **) b;
float aspectA = (float)modeA->w / (float)modeA->h;
float aspectB = (float)modeB->w / (float)modeB->h;
int areaA = modeA->w * modeA->h;
int areaB = modeB->w * modeB->h;
float aspectDiffA = fabs(aspectA - displayAspect);
float aspectDiffB = fabs(aspectB - displayAspect);
float aspectDiffsDiff = aspectDiffA - aspectDiffB;
if(aspectDiffsDiff > ASPECT_EPSILON)
return 1;
else if(aspectDiffsDiff < -ASPECT_EPSILON)
return -1;
else
return areaA - areaB;
}
/*
===============
GLimp_DetectAvailableModes
===============
*/
static void GLimp_DetectAvailableModes(void)
{
char buf[MAX_STRING_CHARS] = { 0 };
SDL_Rect **modes;
int numModes;
int i;
modes = SDL_ListModes(videoInfo->vfmt, SDL_OPENGL | SDL_FULLSCREEN);
if(!modes)
{
ri.Printf(PRINT_WARNING, "Can't get list of available modes\n");
return;
}
if(modes == (SDL_Rect **) - 1)
{
ri.Printf(PRINT_ALL, "Display supports any resolution\n");
return; // can set any resolution
}
for(numModes = 0; modes[numModes]; numModes++);
if(numModes > 1)
qsort(modes, numModes, sizeof(SDL_Rect *), GLimp_CompareModes);
for(i = 0; i < numModes; i++)
{
const char *newModeString = va("%ux%u ", modes[i]->w, modes[i]->h);
if(strlen(newModeString) < (int)sizeof(buf) - strlen(buf))
Q_strcat(buf, sizeof(buf), newModeString);
else
ri.Printf(PRINT_WARNING, "Skipping mode %ux%x, buffer too small\n", modes[i]->w, modes[i]->h);
}
if(*buf)
{
buf[strlen(buf) - 1] = 0;
ri.Printf(PRINT_ALL, "Available modes: '%s'\n", buf);
ri.Cvar_Set("r_availableModes", buf);
}
}
static void GLimp_InitOpenGL3xContext()
{
int retVal;
const char *success[] = { "failed", "success" };
if(!r_glCoreProfile->integer)
return;
GLimp_GetCurrentContext();
// try to initialize an OpenGL 3.0 context
#if defined(WIN32)
if(WGLEW_ARB_create_context || wglewIsSupported("WGL_ARB_create_context"))
{
int attribs[256]; // should be really enough
int numAttribs;
/*
int attribs[] =
{
WGL_CONTEXT_MAJOR_VERSION_ARB, r_glMinMajorVersion->integer,
WGL_CONTEXT_MINOR_VERSION_ARB, r_glMinMinorVersion->integer,
WGL_CONTEXT_FLAGS_ARB,
WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,// | WGL_CONTEXT_DEBUG_BIT_ARB,
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
0
};
*/
memset(attribs, 0, sizeof(attribs));
numAttribs = 0;
attribs[numAttribs++] = WGL_CONTEXT_MAJOR_VERSION_ARB;
attribs[numAttribs++] = r_glMinMajorVersion->integer;
attribs[numAttribs++] = WGL_CONTEXT_MINOR_VERSION_ARB;
attribs[numAttribs++] = r_glMinMinorVersion->integer;
if(WGLEW_ARB_create_context_profile)
{
attribs[numAttribs++] = WGL_CONTEXT_FLAGS_ARB;
#if 0
if(GLXEW_ARB_debug_output)
{
attribs[numAttribs++] = WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB | WGL_CONTEXT_DEBUG_BIT_ARB;
}
else
#endif
{
attribs[numAttribs++] = WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
}
attribs[numAttribs++] = WGL_CONTEXT_PROFILE_MASK_ARB;
attribs[numAttribs++] = WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
}
// set current context to NULL
retVal = wglMakeCurrent(opengl_context.hDC, NULL) != 0;
ri.Printf(PRINT_ALL, "...wglMakeCurrent( %p, %p ): %s\n", opengl_context.hDC, NULL, success[retVal]);
// delete HGLRC
if(opengl_context.hGLRC)
{
retVal = wglDeleteContext(opengl_context.hGLRC) != 0;
ri.Printf(PRINT_ALL, "...deleting standard GL context: %s\n", success[retVal]);
opengl_context.hGLRC = NULL;
}
ri.Printf(PRINT_ALL, "...initializing OpenGL %i.%i context ", r_glMinMajorVersion->integer, r_glMinMinorVersion->integer);
opengl_context.hGLRC = wglCreateContextAttribsARB(opengl_context.hDC, 0, attribs);
if(wglMakeCurrent(opengl_context.hDC, opengl_context.hGLRC))
{
ri.Printf(PRINT_ALL, " done\n");
glConfig.driverType = GLDRV_OPENGL3;
}
else
{
ri.Error(ERR_FATAL, "Could not initialize OpenGL %i.%i context\n"
"Make sure your graphics card supports OpenGL %i.%i or newer",
r_glMinMajorVersion->integer, r_glMinMinorVersion->integer,
r_glMinMajorVersion->integer, r_glMinMinorVersion->integer);
}
}
#elif 0 //defined(__linux__)
// TODO
/*
// GLX_ARB_create_context
#ifndef GLX_ARB_create_context
#define GLX_CONTEXT_DEBUG_BIT_ARB 0x00000001
#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002
#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
#define GLX_CONTEXT_FLAGS_ARB 0x2094
extern GLXContext (APIENTRY * glXCreateContextAttribsARB) (Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list);
*/
glXCreateContextAttribsARB = SDL_GL_GetProcAddress("glXCreateContextAttribsARB");
if(glXCreateContextAttribsARB)
{
int attribs[3];
ri.Printf(PRINT_ALL, "Initializing OpenGL 3.0 context...");
attribs[0] = WGL_CONTEXT_MAJOR_VERSION_ARB;
attribs[1] = 3;
attribs[2] = 0; //terminate first pair
opengl_context->hGLRC = glXCreateContextAttribsARB(opengl_context->, attribs);
if(wglMakeCurrent(opengl_context->hDC, opengl_context->hGLRC))
{
ri.Printf(PRINT_ALL, " done\n");
glConfig.driverType = GLDRV_OPENGL3;
}
else
{
ri.Printf(PRINT_ALL, " failed\n");
}
}
#endif
}
/*
===============
GLimp_SetMode
===============
*/
static int GLimp_SetMode(int mode, qboolean fullscreen, qboolean noborder)
{
const char *glstring;
int sdlcolorbits;
int colorbits, depthbits, stencilbits;
int tcolorbits, tdepthbits, tstencilbits;
int i = 0;
SDL_Surface *vidscreen = NULL;
Uint32 flags = SDL_OPENGL;
GLenum glewResult;
ri.Printf(PRINT_ALL, "Initializing OpenGL display\n");
if(r_allowResize->integer)
flags |= SDL_RESIZABLE;
if(videoInfo == NULL)
{
static SDL_VideoInfo sVideoInfo;
static SDL_PixelFormat sPixelFormat;
videoInfo = SDL_GetVideoInfo();
// Take a copy of the videoInfo
Com_Memcpy(&sPixelFormat, videoInfo->vfmt, sizeof(SDL_PixelFormat));
sPixelFormat.palette = NULL; // Should already be the case
Com_Memcpy(&sVideoInfo, videoInfo, sizeof(SDL_VideoInfo));
sVideoInfo.vfmt = &sPixelFormat;
videoInfo = &sVideoInfo;
if(videoInfo->current_h > 0)
{
// Guess the display aspect ratio through the desktop resolution
// by assuming (relatively safely) that it is set at or close to
// the display's native aspect ratio
displayAspect = (float)videoInfo->current_w / (float)videoInfo->current_h;
ri.Printf(PRINT_ALL, "Estimated display aspect: %.3f\n", displayAspect);
}
else
{
ri.Printf(PRINT_ALL, "Cannot estimate display aspect, assuming 1.333\n");
}
}
ri.Printf(PRINT_ALL, "...setting mode %d:", mode);
if(!R_GetModeInfo(&glConfig.vidWidth, &glConfig.vidHeight, &glConfig.windowAspect, mode))
{
ri.Printf(PRINT_ALL, " invalid mode\n");
return RSERR_INVALID_MODE;
}
ri.Printf(PRINT_ALL, " %d %d\n", glConfig.vidWidth, glConfig.vidHeight);
if(fullscreen)
{
flags |= SDL_FULLSCREEN;
glConfig.isFullscreen = qtrue;
}
else
{
if(noborder)
flags |= SDL_NOFRAME;
glConfig.isFullscreen = qfalse;
}
colorbits = r_colorbits->value;
if((!colorbits) || (colorbits >= 32))
colorbits = 24;
if(!r_depthbits->value)
depthbits = 24;
else
depthbits = r_depthbits->value;
stencilbits = r_stencilbits->value;
for(i = 0; i < 16; i++)
{
// 0 - default
// 1 - minus colorbits
// 2 - minus depthbits
// 3 - minus stencil
if((i % 4) == 0 && i)
{
// one pass, reduce
switch (i / 4)
{
case 2:
if(colorbits == 24)
colorbits = 16;
break;
case 1:
if(depthbits == 24)
depthbits = 16;
else if(depthbits == 16)
depthbits = 8;
case 3:
if(stencilbits == 24)
stencilbits = 16;
else if(stencilbits == 16)
stencilbits = 8;
}
}
tcolorbits = colorbits;
tdepthbits = depthbits;
tstencilbits = stencilbits;
if((i % 4) == 3)
{ // reduce colorbits
if(tcolorbits == 24)
tcolorbits = 16;
}
if((i % 4) == 2)
{ // reduce depthbits
if(tdepthbits == 24)
tdepthbits = 16;
else if(tdepthbits == 16)
tdepthbits = 8;
}
if((i % 4) == 1)
{ // reduce stencilbits
if(tstencilbits == 24)
tstencilbits = 16;
else if(tstencilbits == 16)
tstencilbits = 8;
else
tstencilbits = 0;
}
sdlcolorbits = 4;
if(tcolorbits == 24)
sdlcolorbits = 8;
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, sdlcolorbits);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, sdlcolorbits);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, sdlcolorbits);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, tdepthbits);
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, tstencilbits);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
if(SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, r_swapInterval->integer) < 0)
ri.Printf(PRINT_ALL, "r_swapInterval requires libSDL >= 1.2.10\n");
#ifdef USE_ICON
{
SDL_Surface *icon = SDL_CreateRGBSurfaceFrom((void *)CLIENT_WINDOW_ICON.pixel_data,
CLIENT_WINDOW_ICON.width,
CLIENT_WINDOW_ICON.height,
CLIENT_WINDOW_ICON.bytes_per_pixel * 8,
CLIENT_WINDOW_ICON.bytes_per_pixel * CLIENT_WINDOW_ICON.width,
#ifdef Q3_LITTLE_ENDIAN
0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000
#else
0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF
#endif
);
SDL_WM_SetIcon(icon, NULL);
SDL_FreeSurface(icon);
}
#endif
SDL_WM_SetCaption(CLIENT_WINDOW_TITLE, CLIENT_WINDOW_MIN_TITLE);
SDL_ShowCursor(0);
if(!(vidscreen = SDL_SetVideoMode(glConfig.vidWidth, glConfig.vidHeight, colorbits, flags)))
{
ri.Printf(PRINT_DEVELOPER, "SDL_SetVideoMode failed: %s\n", SDL_GetError());
continue;
}
ri.Printf(PRINT_ALL, "Using %d/%d/%d Color bits, %d depth, %d stencil display.\n",
sdlcolorbits, sdlcolorbits, sdlcolorbits, tdepthbits, tstencilbits);
glConfig.colorBits = tcolorbits;
glConfig.depthBits = tdepthbits;
glConfig.stencilBits = tstencilbits;
break;
}
glewResult = glewInit();
if(GLEW_OK != glewResult)
{
// glewInit failed, something is seriously wrong
ri.Error(ERR_FATAL, "GLW_StartOpenGL() - could not load OpenGL subsystem: %s", glewGetErrorString(glewResult));
}
else
{
ri.Printf(PRINT_ALL, "Using GLEW %s\n", glewGetString(GLEW_VERSION));
}
GLimp_InitOpenGL3xContext();
GLimp_DetectAvailableModes();
if(!vidscreen)
{
ri.Printf(PRINT_ALL, "Couldn't get a visual\n");
return RSERR_INVALID_MODE;
}
screen = vidscreen;
glstring = (char *)glGetString(GL_RENDERER);
ri.Printf(PRINT_ALL, "GL_RENDERER: %s\n", glstring);
return RSERR_OK;
}
/*
===============
GLimp_StartDriverAndSetMode
===============
*/
static qboolean GLimp_StartDriverAndSetMode(int mode, qboolean fullscreen, qboolean noborder)
{
rserr_t err;
if(!SDL_WasInit(SDL_INIT_VIDEO))
{
char driverName[64];
ri.Printf(PRINT_ALL, "SDL_Init( SDL_INIT_VIDEO )... ");
if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE) == -1)
{
ri.Printf(PRINT_ALL, "SDL_Init(SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE) FAILED (%s)\n", SDL_GetError());
return qfalse;
}
SDL_VideoDriverName(driverName, sizeof(driverName) - 1);
ri.Printf(PRINT_ALL, "SDL using driver \"%s\"\n", driverName);
ri.Cvar_Set("r_sdlDriver", driverName);
}
if(fullscreen && ri.Cvar_VariableIntegerValue("in_nograb"))
{
ri.Printf(PRINT_ALL, "Fullscreen not allowed with in_nograb 1\n");
ri.Cvar_Set("r_fullscreen", "0");
r_fullscreen->modified = qfalse;
fullscreen = qfalse;
}
err = GLimp_SetMode(mode, fullscreen, noborder);
switch (err)
{
case RSERR_INVALID_FULLSCREEN:
ri.Printf(PRINT_ALL, "...WARNING: fullscreen unavailable in this mode\n");
return qfalse;
case RSERR_INVALID_MODE:
ri.Printf(PRINT_ALL, "...WARNING: could not set the given mode (%d)\n", mode);
return qfalse;
default:
break;
}
return qtrue;
}
/*
===============
GLimp_InitExtensions
===============
*/
static void GLimp_InitExtensions(void)
{
ri.Printf(PRINT_ALL, "Initializing OpenGL extensions\n");
// GL_ARB_multitexture
if(glConfig.driverType != GLDRV_OPENGL3)
{
if(GLEW_ARB_multitexture)
{
glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &glConfig.numTextureUnits);
if(glConfig.numTextureUnits > 1)
{
ri.Printf(PRINT_ALL, "...using GL_ARB_multitexture\n");
}
else
{
ri.Error(ERR_FATAL, "...not using GL_ARB_multitexture, < 2 texture units\n");
}
}
else
{
ri.Error(ERR_FATAL, "...GL_ARB_multitexture not found\n");
}
}
// GL_ARB_depth_texture
if(GLEW_ARB_depth_texture)
{
ri.Printf(PRINT_ALL, "...using GL_ARB_depth_texture\n");
}
else
{
ri.Error(ERR_FATAL, "...GL_ARB_depth_texture not found\n");
}
// GL_ARB_texture_cube_map
if(GLEW_ARB_texture_cube_map)
{
glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB, &glConfig2.maxCubeMapTextureSize);
ri.Printf(PRINT_ALL, "...using GL_ARB_texture_cube_map\n");
}
else
{
ri.Error(ERR_FATAL, "...GL_ARB_texture_cube_map not found\n");
}
GL_CheckErrors();
// GL_ARB_vertex_program
if(GLEW_ARB_vertex_program)
{
ri.Printf(PRINT_ALL, "...using GL_ARB_vertex_program\n");
}
else
{
ri.Error(ERR_FATAL, "...GL_ARB_vertex_program not found\n");
}
// GL_ARB_vertex_buffer_object
if(GLEW_ARB_vertex_buffer_object)
{
ri.Printf(PRINT_ALL, "...using GL_ARB_vertex_buffer_object\n");
}
else
{
ri.Error(ERR_FATAL, "...GL_ARB_vertex_buffer_object not found\n");
}
// GL_ARB_occlusion_query
glConfig2.occlusionQueryAvailable = qfalse;
glConfig2.occlusionQueryBits = 0;
if(GLEW_ARB_occlusion_query)
{
if(r_ext_occlusion_query->value)
{
glConfig2.occlusionQueryAvailable = qtrue;
glGetQueryivARB(GL_SAMPLES_PASSED, GL_QUERY_COUNTER_BITS, &glConfig2.occlusionQueryBits);
ri.Printf(PRINT_ALL, "...using GL_ARB_occlusion_query\n");
}
else
{
ri.Printf(PRINT_ALL, "...ignoring GL_ARB_occlusion_query\n");
}
}
else
{
ri.Printf(PRINT_ALL, "...GL_ARB_occlusion_query not found\n");
}
GL_CheckErrors();
// GL_ARB_shader_objects
if(GLEW_ARB_shader_objects)
{
ri.Printf(PRINT_ALL, "...using GL_ARB_shader_objects\n");
}
else
{
ri.Error(ERR_FATAL, "...GL_ARB_shader_objects not found\n");
}
// GL_ARB_vertex_shader
if(GLEW_ARB_vertex_shader)
{
int reservedComponents;
GL_CheckErrors();
glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, &glConfig2.maxVertexUniforms); GL_CheckErrors();
//glGetIntegerv(GL_MAX_VARYING_FLOATS_ARB, &glConfig.maxVaryingFloats); GL_CheckErrors();
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &glConfig2.maxVertexAttribs); GL_CheckErrors();
reservedComponents = 16 * 10; // approximation how many uniforms we have besides the bone matrices
/*
if(glConfig.driverType == GLDRV_MESA)
{
// HACK
// restrict to number of vertex uniforms to 512 because of:
// xreal.x86_64: nv50_program.c:4181: nv50_program_validate_data: Assertion `p->param_nr <= 512' failed
glConfig2.maxVertexUniforms = Q_bound(0, glConfig2.maxVertexUniforms, 512);
}
*/
glConfig2.maxVertexSkinningBones = (int) Q_bound(0.0, (Q_max(glConfig2.maxVertexUniforms - reservedComponents, 0) / 16), MAX_BONES);
glConfig2.vboVertexSkinningAvailable = r_vboVertexSkinning->integer && ((glConfig2.maxVertexSkinningBones >= 12) ? qtrue : qfalse);
ri.Printf(PRINT_ALL, "...using GL_ARB_vertex_shader\n");
}
else
{
ri.Error(ERR_FATAL, "...GL_ARB_vertex_shader not found\n");
}
GL_CheckErrors();
// GL_ARB_fragment_shader
if(GLEW_ARB_fragment_shader)
{
ri.Printf(PRINT_ALL, "...using GL_ARB_fragment_shader\n");
}
else
{
ri.Error(ERR_FATAL, "...GL_ARB_fragment_shader not found\n");
}
// GL_ARB_shading_language_100
if(GLEW_ARB_shading_language_100)
{
Q_strncpyz(glConfig2.shadingLanguageVersion, (char*)glGetString(GL_SHADING_LANGUAGE_VERSION_ARB),
sizeof(glConfig2.shadingLanguageVersion));
ri.Printf(PRINT_ALL, "...using GL_ARB_shading_language_100\n");
}
else
{
ri.Printf(ERR_FATAL, "...GL_ARB_shading_language_100 not found\n");
}
GL_CheckErrors();
// GL_ARB_texture_non_power_of_two
glConfig2.textureNPOTAvailable = qfalse;
if(GLEW_ARB_texture_non_power_of_two)
{
if(r_ext_texture_non_power_of_two->integer)
{
glConfig2.textureNPOTAvailable = qtrue;
ri.Printf(PRINT_ALL, "...using GL_ARB_texture_non_power_of_two\n");
}
else
{
ri.Printf(PRINT_ALL, "...ignoring GL_ARB_texture_non_power_of_two\n");
}
}
else
{
ri.Printf(PRINT_ALL, "...GL_ARB_texture_non_power_of_two not found\n");
}
// GL_ARB_draw_buffers
glConfig2.drawBuffersAvailable = qfalse;
if(GLEW_ARB_draw_buffers)
{
glGetIntegerv(GL_MAX_DRAW_BUFFERS_ARB, &glConfig2.maxDrawBuffers);
if(r_ext_draw_buffers->integer)
{
glConfig2.drawBuffersAvailable = qtrue;
ri.Printf(PRINT_ALL, "...using GL_ARB_draw_buffers\n");
}
else
{
ri.Printf(PRINT_ALL, "...ignoring GL_ARB_draw_buffers\n");
}
}
else
{
ri.Printf(PRINT_ALL, "...GL_ARB_draw_buffers not found\n");
}
// GL_ARB_half_float_pixel
glConfig2.textureHalfFloatAvailable = qfalse;
if(GLEW_ARB_half_float_pixel)
{
if(r_ext_half_float_pixel->integer)
{
glConfig2.textureHalfFloatAvailable = qtrue;
ri.Printf(PRINT_ALL, "...using GL_ARB_half_float_pixel\n");
}
else
{
ri.Printf(PRINT_ALL, "...ignoring GL_ARB_half_float_pixel\n");
}
}
else
{
ri.Printf(PRINT_ALL, "...GL_ARB_half_float_pixel not found\n");
}
// GL_ARB_texture_float
glConfig2.textureFloatAvailable = qfalse;
if(GLEW_ARB_texture_float)
{
if(r_ext_texture_float->integer)
{
glConfig2.textureFloatAvailable = qtrue;
ri.Printf(PRINT_ALL, "...using GL_ARB_texture_float\n");
}
else
{
ri.Printf(PRINT_ALL, "...ignoring GL_ARB_texture_float\n");
}
}
else
{
ri.Printf(PRINT_ALL, "...GL_ARB_texture_float not found\n");
}
// GL_ARB_texture_compression
glConfig.textureCompression = TC_NONE;
if(GLEW_ARB_texture_compression)
{
if(r_ext_compressed_textures->integer)
{
glConfig2.ARBTextureCompressionAvailable = qtrue;
ri.Printf(PRINT_ALL, "...using GL_ARB_texture_compression\n");
}
else
{
ri.Printf(PRINT_ALL, "...ignoring GL_ARB_texture_compression\n");
}
}
else
{
ri.Printf(PRINT_ALL, "...GL_ARB_texture_compression not found\n");
}
// GL_ARB_vertex_array_object
glConfig2.vertexArrayObjectAvailable = qfalse;
if(GLEW_ARB_vertex_array_object)
{
if(r_ext_vertex_array_object->integer)
{
glConfig2.vertexArrayObjectAvailable = qtrue;
ri.Printf(PRINT_ALL, "...using GL_ARB_vertex_array_object\n");
}
else
{
ri.Printf(PRINT_ALL, "...ignoring GL_ARB_vertex_array_object\n");
}
}
else
{
ri.Printf(PRINT_ALL, "...GL_ARB_vertex_array_object not found\n");
}
// GL_EXT_texture_compression_s3tc
if(GLEW_EXT_texture_compression_s3tc)
{
if(r_ext_compressed_textures->integer)
{
glConfig.textureCompression = TC_S3TC;
ri.Printf(PRINT_ALL, "...using GL_EXT_texture_compression_s3tc\n");
}
else
{
ri.Printf(PRINT_ALL, "...ignoring GL_EXT_texture_compression_s3tc\n");
}
}
else
{
ri.Printf(PRINT_ALL, "...GL_EXT_texture_compression_s3tc not found\n");
}
// GL_EXT_texture3D
glConfig2.texture3DAvailable = qfalse;
if(GLEW_EXT_texture3D)
{
//if(r_ext_texture3d->value)
{
glConfig2.texture3DAvailable = qtrue;
ri.Printf(PRINT_ALL, "...using GL_EXT_texture3D\n");
}
/*
else
{
ri.Printf(PRINT_ALL, "...ignoring GL_EXT_texture3D\n");
}
*/
}
else
{
ri.Printf(PRINT_ALL, "...GL_EXT_texture3D not found\n");
}
// GL_EXT_stencil_wrap
glConfig2.stencilWrapAvailable = qfalse;
if(GLEW_EXT_stencil_wrap)
{
if(r_ext_stencil_wrap->value)
{
glConfig2.stencilWrapAvailable = qtrue;
ri.Printf(PRINT_ALL, "...using GL_EXT_stencil_wrap\n");
}
else
{
ri.Printf(PRINT_ALL, "...ignoring GL_EXT_stencil_wrap\n");
}
}
else
{
ri.Printf(PRINT_ALL, "...GL_EXT_stencil_wrap not found\n");
}
// GL_EXT_texture_filter_anisotropic
glConfig2.textureAnisotropyAvailable = qfalse;
if(GLEW_EXT_texture_filter_anisotropic)
{
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &glConfig2.maxTextureAnisotropy);
if(r_ext_texture_filter_anisotropic->value)
{
glConfig2.textureAnisotropyAvailable = qtrue;
ri.Printf(PRINT_ALL, "...using GL_EXT_texture_filter_anisotropic\n");
}
else
{
ri.Printf(PRINT_ALL, "...ignoring GL_EXT_texture_filter_anisotropic\n");
}
}
else
{
ri.Printf(PRINT_ALL, "...GL_EXT_texture_filter_anisotropic not found\n");
}
GL_CheckErrors();
// GL_EXT_stencil_two_side
if(GLEW_EXT_stencil_two_side)
{
if(r_ext_stencil_two_side->value)
{
ri.Printf(PRINT_ALL, "...using GL_EXT_stencil_two_side\n");
}
else
{
ri.Printf(PRINT_ALL, "...ignoring GL_EXT_stencil_two_side\n");
}
}
else
{
ri.Printf(PRINT_ALL, "...GL_EXT_stencil_two_side not found\n");
}
// GL_EXT_depth_bounds_test
if(GLEW_EXT_depth_bounds_test)
{
if(r_ext_depth_bounds_test->value)
{
ri.Printf(PRINT_ALL, "...using GL_EXT_depth_bounds_test\n");
}
else
{
ri.Printf(PRINT_ALL, "...ignoring GL_EXT_depth_bounds_test\n");
}
}
else
{
ri.Printf(PRINT_ALL, "...GL_EXT_depth_bounds_test not found\n");
}
// GL_EXT_framebuffer_object
glConfig2.framebufferObjectAvailable = qfalse;
if(GLEW_EXT_framebuffer_object)
{
glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE_EXT, &glConfig2.maxRenderbufferSize);
glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &glConfig2.maxColorAttachments);
if(r_ext_framebuffer_object->value)
{
glConfig2.framebufferObjectAvailable = qtrue;
ri.Printf(PRINT_ALL, "...using GL_EXT_framebuffer_object\n");
}
else
{
ri.Printf(PRINT_ALL, "...ignoring GL_EXT_framebuffer_object\n");
}
}
else
{
ri.Printf(PRINT_ALL, "...GL_EXT_framebuffer_object not found\n");
}
GL_CheckErrors();
// GL_EXT_packed_depth_stencil
glConfig2.framebufferPackedDepthStencilAvailable = qfalse;
if(GLEW_EXT_packed_depth_stencil && glConfig.driverType != GLDRV_MESA)
{
if(r_ext_packed_depth_stencil->integer)
{
glConfig2.framebufferPackedDepthStencilAvailable = qtrue;
ri.Printf(PRINT_ALL, "...using GL_EXT_packed_depth_stencil\n");
}
else
{
ri.Printf(PRINT_ALL, "...ignoring GL_EXT_packed_depth_stencil\n");
}
}
else
{
ri.Printf(PRINT_ALL, "...GL_EXT_packed_depth_stencil not found\n");
}
// GL_EXT_framebuffer_blit
glConfig2.framebufferBlitAvailable = qfalse;
if(GLEW_EXT_framebuffer_blit)
{
if(r_ext_framebuffer_blit->integer)
{
glConfig2.framebufferBlitAvailable = qtrue;
ri.Printf(PRINT_ALL, "...using GL_EXT_framebuffer_blit\n");
}
else
{
ri.Printf(PRINT_ALL, "...ignoring GL_EXT_framebuffer_blit\n");
}
}
else
{
ri.Printf(PRINT_ALL, "...GL_EXT_framebuffer_blit not found\n");
}
// GL_EXTX_framebuffer_mixed_formats
/*
glConfig.framebufferMixedFormatsAvailable = qfalse;
if(GLEW_EXTX_framebuffer_mixed_formats)
{
if(r_extx_framebuffer_mixed_formats->integer)
{
glConfig.framebufferMixedFormatsAvailable = qtrue;
ri.Printf(PRINT_ALL, "...using GL_EXTX_framebuffer_mixed_formats\n");
}
else
{
ri.Printf(PRINT_ALL, "...ignoring GL_EXTX_framebuffer_mixed_formats\n");
}
}
else
{
ri.Printf(PRINT_ALL, "...GL_EXTX_framebuffer_mixed_formats not found\n");
}
*/
// GL_ATI_separate_stencil
if(GLEW_ATI_separate_stencil)
{
if(r_ext_separate_stencil->value)
{
ri.Printf(PRINT_ALL, "...using GL_ATI_separate_stencil\n");
}
else
{
ri.Printf(PRINT_ALL, "...ignoring GL_ATI_separate_stencil\n");
}
}
else
{
ri.Printf(PRINT_ALL, "...GL_ATI_separate_stencil not found\n");
}
// GL_SGIS_generate_mipmap
glConfig2.generateMipmapAvailable = qfalse;
if(GLEW_SGIS_generate_mipmap)
{
if(r_ext_generate_mipmap->value)
{
glConfig2.generateMipmapAvailable = qtrue;
ri.Printf(PRINT_ALL, "...using GL_SGIS_generate_mipmap\n");
}
else
{
ri.Printf(PRINT_ALL, "...ignoring GL_SGIS_generate_mipmap\n");
}
}
else
{
ri.Printf(PRINT_ALL, "...GL_SGIS_generate_mipmap not found\n");
}
// GL_GREMEDY_string_marker
if(GLEW_GREMEDY_string_marker)
{
ri.Printf(PRINT_ALL, "...using GL_GREMEDY_string_marker\n");
}
else
{
ri.Printf(PRINT_ALL, "...GL_GREMEDY_string_marker not found\n");
}
}
#define R_MODE_FALLBACK 3 // 640 * 480
/*
===============
GLimp_Init
This routine is responsible for initializing the OS specific portions
of OpenGL
===============
*/
void GLimp_Init(void)
{
qboolean success = qtrue;
glConfig.driverType = GLDRV_DEFAULT;
r_sdlDriver = ri.Cvar_Get("r_sdlDriver", "", CVAR_ROM);
r_allowResize = ri.Cvar_Get("r_allowResize", "0", CVAR_ARCHIVE);
r_centerWindow = ri.Cvar_Get("r_centerWindow", "0", CVAR_ARCHIVE);
if(ri.Cvar_VariableIntegerValue("com_abnormalExit"))
{
ri.Cvar_Set("r_mode", va("%d", R_MODE_FALLBACK));
ri.Cvar_Set("r_fullscreen", "0");
ri.Cvar_Set("r_centerWindow", "0");
ri.Cvar_Set("com_abnormalExit", "0");
}
//Sys_SetEnv("SDL_VIDEO_CENTERED", r_centerWindow->integer ? "1" : "");
//Sys_GLimpInit();
#if 0 //defined(WIN32)
if(!SDL_VIDEODRIVER_externallySet)
{
// It's a little bit weird having in_mouse control the
// video driver, but from ioq3's point of view they're
// virtually the same except for the mouse input anyway
if(ri.Cvar_VariableIntegerValue("in_mouse") == -1)
{
// Use the windib SDL backend, which is closest to
// the behaviour of idq3 with in_mouse set to -1
_putenv("SDL_VIDEODRIVER=windib");
}
else
{
// Use the DirectX SDL backend
_putenv("SDL_VIDEODRIVER=directx");
}
}
#endif
// Create the window and set up the context
if(GLimp_StartDriverAndSetMode(r_mode->integer, r_fullscreen->integer, qfalse))
goto success;
// Try again, this time in a platform specific "safe mode"
//Sys_GLimpSafeInit();
#if 0 //defined(WIN32)
if(!SDL_VIDEODRIVER_externallySet)
{
// Here, we want to let SDL decide what do to unless
// explicitly requested otherwise
_putenv("SDL_VIDEODRIVER=");
}
#endif
if(GLimp_StartDriverAndSetMode(r_mode->integer, r_fullscreen->integer, qfalse))
goto success;
// Finally, try the default screen resolution
if(r_mode->integer != R_MODE_FALLBACK)
{
ri.Printf(PRINT_ALL, "Setting r_mode %d failed, falling back on r_mode %d\n", r_mode->integer, R_MODE_FALLBACK);
if(GLimp_StartDriverAndSetMode(R_MODE_FALLBACK, qfalse, qfalse))
goto success;
}
// Nothing worked, give up
ri.Error(ERR_FATAL, "GLimp_Init() - could not load OpenGL subsystem\n");
success:
// This values force the UI to disable driver selection
glConfig.hardwareType = GLHW_GENERIC;
glConfig.deviceSupportsGamma = SDL_SetGamma(1.0f, 1.0f, 1.0f) >= 0;
// Mysteriously, if you use an NVidia graphics card and multiple monitors,
// SDL_SetGamma will incorrectly return false... the first time; ask
// again and you get the correct answer. This is a suspected driver bug, see
// http://bugzilla.icculus.org/show_bug.cgi?id=4316
glConfig.deviceSupportsGamma = SDL_SetGamma(1.0f, 1.0f, 1.0f) >= 0;
// get our config strings
Q_strncpyz(glConfig.vendor_string, (char *)glGetString(GL_VENDOR), sizeof(glConfig.vendor_string));
Q_strncpyz(glConfig.renderer_string, (char *)glGetString(GL_RENDERER), sizeof(glConfig.renderer_string));
if(*glConfig.renderer_string && glConfig.renderer_string[strlen(glConfig.renderer_string) - 1] == '\n')
glConfig.renderer_string[strlen(glConfig.renderer_string) - 1] = 0;
Q_strncpyz(glConfig.version_string, (char *)glGetString(GL_VERSION), sizeof(glConfig.version_string));
if(glConfig.driverType != GLDRV_OPENGL3)
{
Q_strncpyz(glConfig.extensions_string, (char *)glGetString(GL_EXTENSIONS), sizeof(glConfig.extensions_string));
}
if( Q_stristr(glConfig.renderer_string, "mesa") ||
Q_stristr(glConfig.renderer_string, "gallium") ||
Q_stristr(glConfig.vendor_string, "nouveau") ||
Q_stristr(glConfig.vendor_string, "mesa"))
{
// suckage
glConfig.driverType = GLDRV_MESA;
}
if(Q_stristr(glConfig.renderer_string, "geforce"))
{
if(Q_stristr(glConfig.renderer_string, "8400") ||
Q_stristr(glConfig.renderer_string, "8500") ||
Q_stristr(glConfig.renderer_string, "8600") ||
Q_stristr(glConfig.renderer_string, "8800") ||
Q_stristr(glConfig.renderer_string, "9500") ||
Q_stristr(glConfig.renderer_string, "9600") ||
Q_stristr(glConfig.renderer_string, "9800") ||
Q_stristr(glConfig.renderer_string, "gts 240") ||
Q_stristr(glConfig.renderer_string, "gts 250") ||
Q_stristr(glConfig.renderer_string, "gtx 260") ||
Q_stristr(glConfig.renderer_string, "gtx 275") ||
Q_stristr(glConfig.renderer_string, "gtx 280") ||
Q_stristr(glConfig.renderer_string, "gtx 285") ||
Q_stristr(glConfig.renderer_string, "gtx 295") ||
Q_stristr(glConfig.renderer_string, "gt 320") ||
Q_stristr(glConfig.renderer_string, "gt 330") ||
Q_stristr(glConfig.renderer_string, "gt 340") ||
Q_stristr(glConfig.renderer_string, "gt 415") ||
Q_stristr(glConfig.renderer_string, "gt 420") ||
Q_stristr(glConfig.renderer_string, "gt 425") ||
Q_stristr(glConfig.renderer_string, "gt 430") ||
Q_stristr(glConfig.renderer_string, "gt 435") ||
Q_stristr(glConfig.renderer_string, "gt 440") ||
Q_stristr(glConfig.renderer_string, "gt 520") ||
Q_stristr(glConfig.renderer_string, "gt 525") ||
Q_stristr(glConfig.renderer_string, "gt 540") ||
Q_stristr(glConfig.renderer_string, "gt 550") ||
Q_stristr(glConfig.renderer_string, "gt 555") ||
Q_stristr(glConfig.renderer_string, "gts 450") ||
Q_stristr(glConfig.renderer_string, "gtx 460") ||
Q_stristr(glConfig.renderer_string, "gtx 470") ||
Q_stristr(glConfig.renderer_string, "gtx 480") ||
Q_stristr(glConfig.renderer_string, "gtx 485") ||
Q_stristr(glConfig.renderer_string, "gtx 560") ||
Q_stristr(glConfig.renderer_string, "gtx 570") ||
Q_stristr(glConfig.renderer_string, "gtx 580") ||
Q_stristr(glConfig.renderer_string, "gtx 590"))
glConfig.hardwareType = GLHW_NV_DX10;
}
else if(Q_stristr(glConfig.renderer_string, "quadro fx"))
{
if(Q_stristr(glConfig.renderer_string, "3600"))
glConfig.hardwareType = GLHW_NV_DX10;
}
else if(Q_stristr(glConfig.renderer_string, "rv770"))
{
glConfig.hardwareType = GLHW_ATI_DX10;
}
else if(Q_stristr(glConfig.renderer_string, "radeon hd"))
{
glConfig.hardwareType = GLHW_ATI_DX10;
}
else if(Q_stristr(glConfig.renderer_string, "eah4850") || Q_stristr(glConfig.renderer_string, "eah4870"))
{
glConfig.hardwareType = GLHW_ATI_DX10;
}
else if(Q_stristr(glConfig.renderer_string, "radeon"))
{
glConfig.hardwareType = GLHW_ATI;
}
// initialize extensions
GLimp_InitExtensions();
ri.Cvar_Get("r_availableModes", "", CVAR_ROM);
// This depends on SDL_INIT_VIDEO, hence having it here
ri.IN_Init();
}
/*
===============
GLimp_EndFrame
Responsible for doing a swapbuffers
===============
*/
void GLimp_EndFrame(void)
{
// don't flip if drawing to front buffer
if(Q_stricmp(r_drawBuffer->string, "GL_FRONT") != 0)
{
SDL_GL_SwapBuffers();
}
if(r_fullscreen->modified)
{
qboolean fullscreen;
qboolean needToToggle = qtrue;
qboolean sdlToggled = qfalse;
SDL_Surface *s = SDL_GetVideoSurface();
if(s)
{
// Find out the current state
fullscreen = !!(s->flags & SDL_FULLSCREEN);
if(r_fullscreen->integer && ri.Cvar_VariableIntegerValue("in_nograb"))
{
ri.Printf(PRINT_ALL, "Fullscreen not allowed with in_nograb 1\n");
ri.Cvar_Set("r_fullscreen", "0");
r_fullscreen->modified = qfalse;
}
// Is the state we want different from the current state?
needToToggle = !!r_fullscreen->integer != fullscreen;
if(needToToggle)
sdlToggled = SDL_WM_ToggleFullScreen(s);
}
if(needToToggle)
{
// SDL_WM_ToggleFullScreen didn't work, so do it the slow way
if(!sdlToggled)
ri.Cmd_ExecuteText(EXEC_APPEND, "vid_restart");
ri.IN_Restart();
}
r_fullscreen->modified = qfalse;
}
}
void GLimp_LogComment(char *comment)
{
static char buf[4096];
if(r_logFile->integer && GLEW_GREMEDY_string_marker)
{
// copy string and ensure it has a trailing '\0'
Q_strncpyz(buf, comment, sizeof(buf));
glStringMarkerGREMEDY(strlen(buf), buf);
}
}