#define MAX_RENDERTARGETS 4
+cvar_t gl_debug = {0, "gl_debug", "0", "enables OpenGL debug output, 0 = off, 1 = HIGH severity only, 2 = also MEDIUM severity, 3 = also LOW severity messages. (note: enabling may not take effect until vid_restart on some drivers)"};
cvar_t gl_paranoid = {0, "gl_paranoid", "0", "enables OpenGL error checking and other tests"};
cvar_t gl_printcheckerror = {0, "gl_printcheckerror", "0", "prints all OpenGL error checks, useful to identify location of driver crashes"};
cvar_t r_renderview = {0, "r_renderview", "1", "enables rendering 3D views (you want this on!)"};
cvar_t r_waterwarp = {CVAR_SAVE, "r_waterwarp", "1", "warp view while underwater"};
cvar_t gl_polyblend = {CVAR_SAVE, "gl_polyblend", "1", "tints view while underwater, hurt, etc"};
-cvar_t gl_dither = {CVAR_SAVE, "gl_dither", "1", "enables OpenGL dithering (16bit looks bad with this off)"};
-cvar_t gl_fbo = {CVAR_SAVE, "gl_fbo", "1", "make use of GL_ARB_framebuffer_object extension to enable shadowmaps and other features using pixel formats different from the framebuffer"};
cvar_t v_flipped = {0, "v_flipped", "0", "mirror the screen (poor man's left handed mode)"};
qboolean v_flipped_state = false;
float gl_modelviewprojection16f[16];
qboolean gl_modelmatrixchanged;
-int gl_maxdrawrangeelementsvertices;
-int gl_maxdrawrangeelementsindices;
-
#ifdef DEBUGGL
int gl_errornumber = 0;
break;
}
}
+
+static void GLAPIENTRY GL_DebugOutputCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const GLvoid* userParam)
+{
+ const char *sev = "ENUM?", *typ = "ENUM?", *src = "ENUM?";
+ switch (severity)
+ {
+ case GL_DEBUG_SEVERITY_LOW_ARB: sev = "LOW"; break;
+ case GL_DEBUG_SEVERITY_MEDIUM_ARB: sev = "MED"; break;
+ case GL_DEBUG_SEVERITY_HIGH_ARB: sev = "HIGH"; break;
+ }
+ switch (type)
+ {
+ case GL_DEBUG_TYPE_ERROR_ARB: typ = "ERROR"; break;
+ case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB: typ = "DEPRECATED"; break;
+ case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB: typ = "UNDEFINED"; break;
+ case GL_DEBUG_TYPE_PORTABILITY_ARB: typ = "PORTABILITY"; break;
+ case GL_DEBUG_TYPE_PERFORMANCE_ARB: typ = "PERFORMANCE"; break;
+ case GL_DEBUG_TYPE_OTHER_ARB: typ = "OTHER"; break;
+ }
+ switch (source)
+ {
+ case GL_DEBUG_SOURCE_API_ARB: src = "API"; break;
+ case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB: src = "SHADER"; break;
+ case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB: src = "WIN"; break;
+ case GL_DEBUG_SOURCE_THIRD_PARTY_ARB: src = "THIRDPARTY"; break;
+ case GL_DEBUG_SOURCE_APPLICATION_ARB: src = "APP"; break;
+ case GL_DEBUG_SOURCE_OTHER_ARB: src = "OTHER"; break;
+ }
+ Con_Printf("GLDEBUG: %s %s %s: %u: %s\n", sev, typ, src, (unsigned int)id, message);
+}
#endif
#define BACKENDACTIVECHECK if (!gl_state.active) Sys_Error("GL backend function called when backend is not active");
rtexture_t *texture;
int t2d, t3d, tcubemap;
int arrayenabled;
- int rgbscale, alphascale;
- int combine;
- int combinergb, combinealpha;
- // texmatrixenabled exists only to avoid unnecessary texmatrix compares
- int texmatrixenabled;
- matrix4x4_t matrix;
}
gltextureunit_t;
int depthfunc;
float depthrange[2];
float polygonoffset[2];
- int alphatest;
- int alphafunc;
- float alphafuncvalue;
qboolean alphatocoverage;
int scissortest;
unsigned int unit;
- unsigned int clientunit;
gltextureunit_t units[MAX_TEXTUREUNITS];
float color4f[4];
int lockrange_first;
Cvar_RegisterVariable(&r_waterwarp);
Cvar_RegisterVariable(&gl_polyblend);
Cvar_RegisterVariable(&v_flipped);
- Cvar_RegisterVariable(&gl_dither);
+ Cvar_RegisterVariable(&gl_debug);
Cvar_RegisterVariable(&gl_paranoid);
Cvar_RegisterVariable(&gl_printcheckerror);
// unbind any matching textures immediately, otherwise D3D will complain about a bound texture being used as a render target
for (j = 0;j < 5;j++)
if (textures[j])
- for (i = 0;i < vid.teximageunits;i++)
+ for (i = 0;i < MAX_TEXTUREUNITS;i++)
if (gl_state.units[i].texture == textures[j])
R_Mesh_TexBind(i, NULL);
// set up framebuffer object or render targets for the active rendering API
static void GL_Backend_ResetState(void)
{
- unsigned int i;
gl_state.active = true;
gl_state.depthtest = true;
- gl_state.alphatest = false;
- gl_state.alphafunc = GL_GEQUAL;
- gl_state.alphafuncvalue = 0.5f;
gl_state.alphatocoverage = false;
gl_state.blendfunc1 = GL_ONE;
gl_state.blendfunc2 = GL_ZERO;
{
case RENDERPATH_GL32:
case RENDERPATH_GLES2:
+ // set up debug output early
+ if (vid.support.arb_debug_output)
+ {
+ GLuint unused = 0;
+ CHECKGLERROR
+ if (gl_debug.integer >= 1)
+ qglEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
+ if (gl_debug.integer >= 3)
+ qglDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, &unused, gl_debug.integer >= 3 ? GL_TRUE : GL_FALSE);
+ else if (gl_debug.integer >= 1)
+ {
+ qglDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW_ARB, 0, &unused, gl_debug.integer >= 3 ? GL_TRUE : GL_FALSE);
+ qglDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_MEDIUM_ARB, 0, &unused, gl_debug.integer >= 2 ? GL_TRUE : GL_FALSE);
+ qglDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_HIGH_ARB, 0, &unused, gl_debug.integer >= 1 ? GL_TRUE : GL_FALSE);
+ }
+ else
+ qglDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, &unused, GL_FALSE);
+ qglDebugMessageCallbackARB(GL_DebugOutputCallback, NULL);
+ }
CHECKGLERROR
qglColorMask(1, 1, 1, 1);CHECKGLERROR
qglBlendFunc(gl_state.blendfunc1, gl_state.blendfunc2);CHECKGLERROR
qglDisableVertexAttribArray(GLSLATTRIB_COLOR);
qglVertexAttrib4f(GLSLATTRIB_COLOR, 1, 1, 1, 1);
gl_state.unit = MAX_TEXTUREUNITS;
- gl_state.clientunit = MAX_TEXTUREUNITS;
- for (i = 0;i < vid.teximageunits;i++)
- {
- GL_ActiveTexture(i);
- qglBindTexture(GL_TEXTURE_2D, 0);CHECKGLERROR
- qglBindTexture(GL_TEXTURE_3D, 0);CHECKGLERROR
- qglBindTexture(GL_TEXTURE_CUBE_MAP, 0);CHECKGLERROR
- }
- for (i = 0;i < vid.texarrayunits;i++)
- {
- GL_BindVBO(0);
- qglDisableVertexAttribArray(i+GLSLATTRIB_TEXCOORD0);CHECKGLERROR
- }
CHECKGLERROR
break;
}
void R_Mesh_TexCoordPointer(unsigned int unitnum, int components, int gltype, size_t stride, const void *pointer, const r_meshbuffer_t *vertexbuffer, size_t bufferoffset)
{
gltextureunit_t *unit = gl_state.units + unitnum;
+ if (unitnum >= MAX_TEXTUREUNITS)
+ Sys_Error("R_Mesh_TexCoordPointer: unitnum %i > max units %i\n", unitnum, MAX_TEXTUREUNITS);
// update array settings
// note: there is no need to check bufferobject here because all cases
// that involve a valid bufferobject also supply a texcoord array
int R_Mesh_TexBound(unsigned int unitnum, int id)
{
gltextureunit_t *unit = gl_state.units + unitnum;
- if (unitnum >= vid.teximageunits)
- return 0;
+ if (unitnum >= MAX_TEXTUREUNITS)
+ Sys_Error("R_Mesh_TexCoordPointer: unitnum %i > max units %i\n", unitnum, MAX_TEXTUREUNITS);
if (id == GL_TEXTURE_2D)
return unit->t2d;
if (id == GL_TEXTURE_3D)
{
gltextureunit_t *unit;
unsigned int unitnum;
- // this doesn't really unbind the texture, but it does prevent a mistaken "do nothing" behavior on the next time this same texnum is bound on the same unit as the same type (this mainly affects r_shadow_bouncegrid because 3D textures are so rarely used)
- for (unitnum = 0;unitnum < vid.teximageunits;unitnum++)
+ // unbind the texture from any units it is bound on - this prevents accidental reuse of certain textures whose bindings can linger far too long otherwise (e.g. bouncegrid which is a 3D texture) and confuse the driver later.
+ for (unitnum = 0; unitnum < MAX_TEXTUREUNITS; unitnum++)
{
unit = gl_state.units + unitnum;
- if (unit->t2d == texnum)
- unit->t2d = -1;
- if (unit->t3d == texnum)
- unit->t3d = -1;
- if (unit->tcubemap == texnum)
- unit->tcubemap = -1;
+ if (unit->texture && unit->texture->texnum == texnum)
+ R_Mesh_TexBind(unitnum, NULL);
}
}
{
gltextureunit_t *unit = gl_state.units + unitnum;
int texnum;
- if (unitnum >= vid.teximageunits)
- return;
+ if (unitnum >= MAX_TEXTUREUNITS)
+ Sys_Error("R_Mesh_TexBind: unitnum %i > max units %i\n", unitnum, MAX_TEXTUREUNITS);
if (unit->texture == tex)
return;
switch(vid.renderpath)
BACKENDACTIVECHECK
- for (unitnum = 0;unitnum < vid.teximageunits;unitnum++)
+ for (unitnum = 0;unitnum < MAX_TEXTUREUNITS;unitnum++)
R_Mesh_TexBind(unitnum, NULL);
- for (unitnum = 0;unitnum < vid.texarrayunits;unitnum++)
- R_Mesh_TexCoordPointer(unitnum, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
}
void R_Mesh_PrepareVertices_Vertex3f(int numvertices, const float *vertex3f, const r_meshbuffer_t *vertexbuffer, int bufferoffset)
// upload temporary vertexbuffer for this rendering
if (!vertexbuffer)
vertexbuffer = R_BufferData_Store(numvertices * sizeof(float[3]), (void *)vertex3f, R_BUFFERDATA_VERTEX, &bufferoffset);
- if (vertexbuffer)
- {
- R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, vertexbuffer, bufferoffset);
- R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL, NULL, 0);
- R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
- R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
- R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
- R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
- R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
- R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
- R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL, NULL, 0);
- R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL, NULL, 0);
- }
- else
- {
- R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, vertexbuffer, 0);
- R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL, NULL, 0);
- R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
- R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
- R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
- R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
- R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
- R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
- R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL, NULL, 0);
- R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL, NULL, 0);
- }
+ R_Mesh_VertexPointer( 3, GL_FLOAT , sizeof(float[3]) , vertex3f , vertexbuffer , bufferoffset );
+ R_Mesh_ColorPointer( 4, GL_FLOAT , sizeof(float[4]) , NULL , NULL , 0 );
+ R_Mesh_TexCoordPointer(0, 2, GL_FLOAT , sizeof(float[2]) , NULL , NULL , 0 );
+ R_Mesh_TexCoordPointer(1, 3, GL_FLOAT , sizeof(float[3]) , NULL , NULL , 0 );
+ R_Mesh_TexCoordPointer(2, 3, GL_FLOAT , sizeof(float[3]) , NULL , NULL , 0 );
+ R_Mesh_TexCoordPointer(3, 3, GL_FLOAT , sizeof(float[3]) , NULL , NULL , 0 );
+ R_Mesh_TexCoordPointer(4, 2, GL_FLOAT , sizeof(float[2]) , NULL , NULL , 0 );
+ R_Mesh_TexCoordPointer(5, 2, GL_FLOAT , sizeof(float[2]) , NULL , NULL , 0 );
+ R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL , NULL , 0 );
+ R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), NULL , NULL , 0 );
}
void R_Mesh_PrepareVertices_Generic_Arrays(int numvertices, const float *vertex3f, const float *color4f, const float *texcoord2f)