Overbright bits hack. FP16 FBO's with r_ext_framebuffer_object 2. Occlusion query for god rays.

This commit is contained in:
Andrei Drexler 2011-03-26 23:01:47 +00:00
parent 3a6ad64407
commit 5df45cf52b
7 changed files with 211 additions and 46 deletions

View file

@ -24,7 +24,11 @@
HANDLE_EXT_FUNC( PFNGLGETQUERYOBJECTIVARBPROC, glGetQueryObjectivARB) \ HANDLE_EXT_FUNC( PFNGLGETQUERYOBJECTIVARBPROC, glGetQueryObjectivARB) \
HANDLE_EXT_FUNC( PFNGLGETQUERYOBJECTUIVARBPROC, glGetQueryObjectuivARB) \ HANDLE_EXT_FUNC( PFNGLGETQUERYOBJECTUIVARBPROC, glGetQueryObjectuivARB) \
#define GL_MISSING_FUNCTIONS \
HANDLE_EXT_FUNC( PFNGLBLENDEQUATIONPROC, glBlendEquation) \
#define GL_ARB_color_buffer_float_functions \
HANDLE_EXT_FUNC( PFNGLCLAMPCOLORARBPROC, glClampColorARB) \
#ifndef GL_EXT_framebuffer_multisample #ifndef GL_EXT_framebuffer_multisample
#define GL_EXT_framebuffer_multisample 1 #define GL_EXT_framebuffer_multisample 1
@ -57,6 +61,7 @@
GL_EXT_framebuffer_multisample_functions \ GL_EXT_framebuffer_multisample_functions \
GL_EXT_framebuffer_blit_functions \ GL_EXT_framebuffer_blit_functions \
GL_ARB_occlusion_query_functions \ GL_ARB_occlusion_query_functions \
GL_ARB_color_buffer_float_functions \
GL_MISSING_FUNCTIONS \
#endif #endif

View file

@ -601,6 +601,7 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
float originalTime; float originalTime;
float depth[2]; float depth[2];
fbo_t* fbo = NULL; fbo_t* fbo = NULL;
qboolean inQuery = qfalse;
// save original time for entity shader offsets // save original time for entity shader offsets
originalTime = backEnd.refdef.floatTime; originalTime = backEnd.refdef.floatTime;
@ -665,6 +666,10 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
{ {
R_FBO_Bind(fbo); R_FBO_Bind(fbo);
qglDepthRange(depth[0], depth[1]); qglDepthRange(depth[0], depth[1]);
if (inQuery) {
inQuery = qfalse;
qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
}
} }
if ( entityNum != ENTITYNUM_WORLD ) { if ( entityNum != ENTITYNUM_WORLD ) {
@ -687,11 +692,16 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
// if we're rendering to a fbo // if we're rendering to a fbo
if (fbo) { if (fbo) {
VectorCopy(backEnd.currentEntity->e.origin, backEnd.sunFlarePos); VectorCopy(backEnd.currentEntity->e.origin, backEnd.sunFlarePos);
backEnd.hasSunFlare = qtrue;
sunflare = qtrue;
// switch FBO // switch FBO
R_FBO_Bind(tr.fbo.fbos[1]); R_FBO_Bind(tr.fbo.fbos[1]);
qglDepthRange(1.f, 1.f); qglDepthRange(1.f, 1.f);
if (glRefConfig.occlusionQuery && !inQuery && !backEnd.hasSunFlare) {
inQuery = qtrue;
tr.sunFlareQueryActive[tr.sunFlareQueryIndex] = qtrue;
qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, tr.sunFlareQuery[tr.sunFlareQueryIndex]);
}
backEnd.hasSunFlare = qtrue;
sunflare = qtrue;
} else { } else {
depthRange = qtrue; depthRange = qtrue;
} }
@ -785,6 +795,10 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
} }
R_FBO_Bind(fbo); R_FBO_Bind(fbo);
if (inQuery) {
inQuery = qfalse;
qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
}
// go back to the world modelview matrix // go back to the world modelview matrix

View file

@ -1,9 +1,5 @@
#include "tr_local.h" #include "tr_local.h"
#ifndef ARRAY_SIZE
# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
#endif
#define MAX_FBO_COLOR_BUFFERS 8 #define MAX_FBO_COLOR_BUFFERS 8
/* /*
@ -426,6 +422,18 @@ static void R_FBO_CreateDefaultBuffers(void)
NULL, NULL,
NULL); NULL);
tr.fbo.tiny[0] = R_FBO_CreateSimple(
"tiny0",
R_FBO_CreateColorBuffer("*tinyBuffer0", glConfig.vidWidth/4, glConfig.vidHeight/4, qfalse, qfalse, GL_CLAMP_TO_EDGE),
NULL,
NULL);
tr.fbo.tiny[1] = R_FBO_CreateSimple(
"tiny1",
R_FBO_CreateColorBuffer("*tinyBuffer1", glConfig.vidWidth/4, glConfig.vidHeight/4, qfalse, qfalse, GL_CLAMP_TO_EDGE),
NULL,
NULL);
ri.Printf(PRINT_DEVELOPER, "...created %d FBOs\n", tr.fbo.numFBOs); ri.Printf(PRINT_DEVELOPER, "...created %d FBOs\n", tr.fbo.numFBOs);
} }

View file

@ -501,11 +501,19 @@ static void Upload32( unsigned *data,
GLenum internalFormat = GL_RGB; GLenum internalFormat = GL_RGB;
float rMax = 0, gMax = 0, bMax = 0; float rMax = 0, gMax = 0, bMax = 0;
// Makro - render target // Makro - no data, this must be a render target
if (!data) if (!data)
{
if (r_ext_framebuffer_object->integer >= 2 && glRefConfig.textureFloat)
{
internalFormat = GL_RGBA16F_ARB;
qglTexImage2D (GL_TEXTURE_2D, 0, internalFormat, width, height, 0, GL_RGBA, GL_FLOAT, NULL);
}
else
{ {
internalFormat = GL_RGBA8; internalFormat = GL_RGBA8;
qglTexImage2D (GL_TEXTURE_2D, 0, internalFormat, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); qglTexImage2D (GL_TEXTURE_2D, 0, internalFormat, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
}
GL_CheckErrors(); GL_CheckErrors();
*format = internalFormat; *format = internalFormat;
*pUploadWidth = width; *pUploadWidth = width;
@ -777,19 +785,45 @@ done:
ri.Hunk_FreeTempMemory( resampledBuffer ); ri.Hunk_FreeTempMemory( resampledBuffer );
} }
static image_t *R_AllocImage(const char* name, int width, int height, qboolean mipmap, qboolean allowPicmip, int glWrapClampMode)
{
image_t *image;
long hash;
image = tr.images[tr.numImages++] = ri.Hunk_Alloc( sizeof( image_t ), h_low );
Com_Memset(image, 0, sizeof(*image));
image->texnum = 1024 + tr.numImages;
image->mipmap = mipmap;
image->allowPicmip = allowPicmip;
strcpy (image->imgName, name);
image->width = width;
image->height = height;
image->wrapClampMode = glWrapClampMode;
hash = generateHashValue(name);
image->next = hashTable[hash];
hashTable[hash] = image;
return image;
}
/* /*
================ ================
R_CreateImage R_CreateImage
This is the only way any image_t are created This is the only way any image_t are created
Makro - except maybe for render targets
at some point in the near future...
================ ================
*/ */
image_t *R_CreateImage( const char *name, const byte *pic, int width, int height, image_t *R_CreateImage( const char *name, const byte *pic, int width, int height,
qboolean mipmap, qboolean allowPicmip, int glWrapClampMode ) { qboolean mipmap, qboolean allowPicmip, int glWrapClampMode ) {
image_t *image; image_t *image;
qboolean isLightmap = qfalse; qboolean isLightmap = qfalse;
long hash;
if (strlen(name) >= MAX_QPATH ) { if (strlen(name) >= MAX_QPATH ) {
ri.Error (ERR_DROP, "R_CreateImage: \"%s\" is too long\n", name); ri.Error (ERR_DROP, "R_CreateImage: \"%s\" is too long\n", name);
@ -802,18 +836,7 @@ image_t *R_CreateImage( const char *name, const byte *pic, int width, int height
ri.Error( ERR_DROP, "R_CreateImage: MAX_DRAWIMAGES hit\n"); ri.Error( ERR_DROP, "R_CreateImage: MAX_DRAWIMAGES hit\n");
} }
image = tr.images[tr.numImages] = ri.Hunk_Alloc( sizeof( image_t ), h_low ); image = R_AllocImage(name, width, height, mipmap, allowPicmip, glWrapClampMode);
image->texnum = 1024 + tr.numImages;
tr.numImages++;
image->mipmap = mipmap;
image->allowPicmip = allowPicmip;
strcpy (image->imgName, name);
image->width = width;
image->height = height;
image->wrapClampMode = glWrapClampMode;
// lightmaps are always allocated on TMU 1 // lightmaps are always allocated on TMU 1
if ( qglActiveTextureARB && isLightmap ) { if ( qglActiveTextureARB && isLightmap ) {
@ -845,10 +868,6 @@ image_t *R_CreateImage( const char *name, const byte *pic, int width, int height
GL_SelectTexture( 0 ); GL_SelectTexture( 0 );
} }
hash = generateHashValue(name);
image->next = hashTable[hash];
hashTable[hash] = image;
return image; return image;
} }
@ -1226,12 +1245,12 @@ void R_SetColorMappings( void ) {
// setup the overbright lighting // setup the overbright lighting
tr.overbrightBits = r_overBrightBits->integer; tr.overbrightBits = r_overBrightBits->integer;
if ( !glConfig.deviceSupportsGamma ) { if ( !glConfig.deviceSupportsGamma && !glRefConfig.glslOverbright ) {
tr.overbrightBits = 0; // need hardware gamma for overbright tr.overbrightBits = 0; // need hardware gamma for overbright
} }
// never overbright in windowed mode // never overbright in windowed mode
if ( !glConfig.isFullscreen ) if ( !glConfig.isFullscreen && !glRefConfig.glslOverbright )
{ {
tr.overbrightBits = 0; tr.overbrightBits = 0;
} }
@ -1268,6 +1287,9 @@ void R_SetColorMappings( void ) {
shift = tr.overbrightBits; shift = tr.overbrightBits;
if (glRefConfig.glslOverbright)
shift = 0;
for ( i = 0; i < 256; i++ ) { for ( i = 0; i < 256; i++ ) {
if ( g == 1 ) { if ( g == 1 ) {
inf = i; inf = i;

View file

@ -410,7 +410,7 @@ void RB_TakeScreenshotJPEG( int x, int y, int width, int height, char *fileName
buffer = ri.Hunk_AllocateTempMemory(glConfig.vidWidth*glConfig.vidHeight*4); buffer = ri.Hunk_AllocateTempMemory(glConfig.vidWidth*glConfig.vidHeight*4);
qglReadPixels( x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer ); qglReadPixels( x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer );
// gamma correct // gamma correct
if ( glConfig.deviceSupportsGamma ) { if ( glConfig.deviceSupportsGamma ) {
@ -430,6 +430,7 @@ RB_TakeScreenshotCmd
*/ */
const void *RB_TakeScreenshotCmd( const void *data ) { const void *RB_TakeScreenshotCmd( const void *data ) {
const screenshotCommand_t *cmd; const screenshotCommand_t *cmd;
fbo_t *fbo = R_FBO_Bind(NULL);
cmd = (const screenshotCommand_t *)data; cmd = (const screenshotCommand_t *)data;
@ -438,6 +439,8 @@ const void *RB_TakeScreenshotCmd( const void *data ) {
else else
RB_TakeScreenshot( cmd->x, cmd->y, cmd->width, cmd->height, cmd->fileName); RB_TakeScreenshot( cmd->x, cmd->y, cmd->width, cmd->height, cmd->fileName);
R_FBO_Bind(fbo);
return (const void *)(cmd + 1); return (const void *)(cmd + 1);
} }
@ -710,12 +713,17 @@ const void *RB_TakeVideoFrameCmd( const void *data )
const videoFrameCommand_t *cmd; const videoFrameCommand_t *cmd;
int frameSize; int frameSize;
int i; int i;
fbo_t *fbo;
cmd = (const videoFrameCommand_t *)data; cmd = (const videoFrameCommand_t *)data;
fbo = R_FBO_Bind(NULL);
qglReadPixels( 0, 0, cmd->width, cmd->height, GL_RGBA, qglReadPixels( 0, 0, cmd->width, cmd->height, GL_RGBA,
GL_UNSIGNED_BYTE, cmd->captureBuffer ); GL_UNSIGNED_BYTE, cmd->captureBuffer );
R_FBO_Bind(fbo);
// gamma correct // gamma correct
if( glConfig.deviceSupportsGamma ) if( glConfig.deviceSupportsGamma )
R_GammaCorrect( cmd->captureBuffer, cmd->width * cmd->height * 4 ); R_GammaCorrect( cmd->captureBuffer, cmd->width * cmd->height * 4 );
@ -1070,12 +1078,16 @@ void R_InitQueries(void)
{ {
if (!glRefConfig.occlusionQuery) if (!glRefConfig.occlusionQuery)
return; return;
qglGenQueriesARB(ARRAY_SIZE(tr.sunFlareQuery), tr.sunFlareQuery);
} }
void R_ShutDownQueries(void) void R_ShutDownQueries(void)
{ {
if (!glRefConfig.occlusionQuery) if (!glRefConfig.occlusionQuery)
return; return;
qglDeleteQueriesARB(ARRAY_SIZE(tr.sunFlareQuery), tr.sunFlareQuery);
} }
/* /*

View file

@ -43,6 +43,10 @@ long myftol( float f );
#define BUFFER_OFFSET(i) ((char *)NULL + (i)) #define BUFFER_OFFSET(i) ((char *)NULL + (i))
#ifndef ARRAY_SIZE
# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
#endif
// everything that is needed by the backend needs // everything that is needed by the backend needs
// to be double buffered to allow it to run in // to be double buffered to allow it to run in
// parallel on a dual cpu machine // parallel on a dual cpu machine
@ -2166,6 +2170,11 @@ typedef struct {
qboolean framebufferBlit; qboolean framebufferBlit;
qboolean framebufferMultisample; qboolean framebufferMultisample;
qboolean glslOverbright;
qboolean textureFloat;
qboolean colorBufferFloat;
qboolean occlusionQuery; qboolean occlusionQuery;
// These next three are all required for one chunk of code, so glsl is // These next three are all required for one chunk of code, so glsl is
@ -2229,6 +2238,7 @@ typedef struct {
fbo_t *full[2]; // full resolution, shared zbuffer fbo_t *full[2]; // full resolution, shared zbuffer
fbo_t *quarter[2]; // quarter resolution, no zbuffer fbo_t *quarter[2]; // quarter resolution, no zbuffer
fbo_t *tiny[2]; // 1/16 resolution, no zbuffer
int numFBOs; int numFBOs;
fbo_t *fbos[1024]; fbo_t *fbos[1024];
@ -2352,6 +2362,10 @@ typedef struct {
int numSkins; int numSkins;
skin_t *skins[MAX_SKINS]; skin_t *skins[MAX_SKINS];
GLuint sunFlareQuery[2];
int sunFlareQueryIndex;
qboolean sunFlareQueryActive[2];
float sinTable[FUNCTABLE_SIZE]; float sinTable[FUNCTABLE_SIZE];
float squareTable[FUNCTABLE_SIZE]; float squareTable[FUNCTABLE_SIZE];
float triangleTable[FUNCTABLE_SIZE]; float triangleTable[FUNCTABLE_SIZE];

View file

@ -158,6 +158,35 @@ static void RB_RadialBlur(int passes, float stretch, float x, float y, float w,
RB_Color4f(1.f, 1.f, 1.f, 1.f); RB_Color4f(1.f, 1.f, 1.f, 1.f);
} }
static qboolean RB_UpdateSunFlareVis(void)
{
GLuint sampleCount = 0;
if (!glRefConfig.occlusionQuery)
return qtrue;
tr.sunFlareQueryIndex ^= 1;
if (!tr.sunFlareQueryActive[tr.sunFlareQueryIndex])
return qtrue;
/* debug code */
if (0)
{
int iter;
for (iter=0 ; ; ++iter)
{
GLint available = 0;
qglGetQueryObjectivARB(tr.sunFlareQuery[tr.sunFlareQueryIndex], GL_QUERY_RESULT_AVAILABLE_ARB, &available);
if (available)
break;
}
ri.Printf(PRINT_DEVELOPER, "Waited %d iterations\n", iter);
}
qglGetQueryObjectuivARB(tr.sunFlareQuery[tr.sunFlareQueryIndex], GL_QUERY_RESULT_ARB, &sampleCount);
return sampleCount > 0;
}
/* /*
================ ================
RB_GodRays RB_GodRays
@ -186,6 +215,9 @@ static void RB_GodRays(void)
if (dot < cutoff) if (dot < cutoff)
return; return;
if (!RB_UpdateSunFlareVis())
return;
VectorCopy(backEnd.sunFlarePos, pos); VectorCopy(backEnd.sunFlarePos, pos);
pos[3] = 1.f; pos[3] = 1.f;
@ -202,8 +234,8 @@ static void RB_GodRays(void)
// viewport dimensions // viewport dimensions
w = glConfig.vidWidth; w = glConfig.vidWidth;
h = glConfig.vidHeight; h = glConfig.vidHeight;
w2 = w * 0.5f; w2 = glConfig.vidWidth / 2;
h2 = h * 0.5f; h2 = glConfig.vidHeight / 2;
// initialize quarter buffers // initialize quarter buffers
{ {
@ -212,7 +244,7 @@ static void RB_GodRays(void)
RB_SetGL2D_Level(1); RB_SetGL2D_Level(1);
GL_State(GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); GL_State(GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO );
RB_Color4f(1.f, 1.f, 1.f, 1.f); RB_Color4f(mul, mul, mul, 1.f);
// first, downsample the main framebuffers // first, downsample the main framebuffers
R_FBO_Bind(tr.fbo.quarter[0]); R_FBO_Bind(tr.fbo.quarter[0]);
@ -245,15 +277,67 @@ static void RB_GodRays(void)
// add result back on top of the main buffer // add result back on top of the main buffer
{ {
float mul = 1.f;
R_FBO_BindColorBuffer(R_FBO_Bind(tr.fbo.full[0]), 0); R_FBO_BindColorBuffer(R_FBO_Bind(tr.fbo.full[0]), 0);
RB_SetGL2D_Level(0); RB_SetGL2D_Level(0);
GL_State(GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); GL_State(GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
RB_Color4f(1.f, 1.f, 1.f, 1.f); RB_Color4f(mul, mul, mul, 1.f);
RB_DrawQuad(0.f, 0.f, w, h, 0.f, 0.f, 1.f, 1.f); RB_DrawQuad(0.f, 0.f, w, h, 0.f, 0.f, 1.f, 1.f);
} }
} }
static void RB_BlurAxis(float w, float h, qboolean horizontal)
{
float dx, dy;
float xmul, ymul;
float weights[3] = {
0.316216216f,
0.227027027f,
0.070270270f,
};
float offsets[3] = {
0.f,
1.3846153846f,
3.2307692308f,
};
xmul = horizontal;
ymul = 1.f - xmul;
xmul /= w;
ymul /= h;
GL_State(GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO );
RB_Color4f(weights[0], weights[0], weights[0], 1.f);
RB_DrawQuad(0.f, 0.f, w, h, 0.f, 0.f, 1.f, 1.f);
GL_State(GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
RB_Color4f(weights[1], weights[1], weights[1], 1.f);
dx = offsets[1] * xmul;
dy = offsets[1] * ymul;
RB_DrawQuad(0.f, 0.f, w, h, dx, dy, 1.f+dx, 1.f+dy);
RB_DrawQuad(0.f, 0.f, w, h, -dx, -dy, 1.f-dx, 1.f-dy);
RB_Color4f(weights[2], weights[2], weights[2], 1.f);
dx = offsets[2] * xmul;
dy = offsets[2] * ymul;
RB_DrawQuad(0.f, 0.f, w, h, dx, dy, 1.f+dx, 1.f+dy);
RB_DrawQuad(0.f, 0.f, w, h, -dx, -dy, 1.f-dx, 1.f-dy);
}
static void RB_HBlur(float w, float h)
{
RB_BlurAxis(w, h, qtrue);
}
static void RB_VBlur(float w, float h)
{
RB_BlurAxis(w, h, qfalse);
}
void RB_FBO_Set2D(void) void RB_FBO_Set2D(void)
{ {
RB_DrawQuad = NULL; RB_DrawQuad = NULL;
@ -321,6 +405,12 @@ void RB_FBO_Blit(void)
R_FBO_BindColorBuffer(fbo, 0); R_FBO_BindColorBuffer(fbo, 0);
GL_State(GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); GL_State(GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO );
if (glRefConfig.glslOverbright)
{
float mul = 1.f / tr.identityLight;
RB_Color4f(mul, mul, mul, 1.f);
}
RB_DrawQuad(0.f, 0.f, glConfig.vidWidth, glConfig.vidHeight, 0.f, 0.f, 1.f, 1.f); RB_DrawQuad(0.f, 0.f, glConfig.vidWidth, glConfig.vidHeight, 0.f, 0.f, 1.f, 1.f);
R_FBO_Bind(fbo); R_FBO_Bind(fbo);
@ -334,7 +424,7 @@ RB_PostProcess
void RB_PostProcess(void) void RB_PostProcess(void)
{ {
if (!glState.currentFBO) if (!glState.currentFBO || backEnd.refdef.rdflags & RDF_NOWORLDMODEL)
return; return;
RB_FBO_Set2D(); RB_FBO_Set2D();