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

@ -14,17 +14,21 @@
HANDLE_EXT_FUNC( PFNGLRENDERBUFFERSTORAGEEXTPROC, glRenderbufferStorageEXT) \
HANDLE_EXT_FUNC( PFNGLBINDRENDERBUFFEREXTPROC, glBindRenderbufferEXT) \
#define GL_ARB_occlusion_query_functions \
HANDLE_EXT_FUNC( PFNGLGENQUERIESARBPROC, glGenQueriesARB) \
HANDLE_EXT_FUNC( PFNGLDELETEQUERIESARBPROC, glDeleteQueriesARB) \
HANDLE_EXT_FUNC( PFNGLISQUERYARBPROC, glIsQueryARB) \
HANDLE_EXT_FUNC( PFNGLBEGINQUERYARBPROC, glBeginQueryARB) \
HANDLE_EXT_FUNC( PFNGLENDQUERYARBPROC, glEndQueryARB) \
HANDLE_EXT_FUNC( PFNGLGETQUERYIVARBPROC, glGetQueryivARB) \
HANDLE_EXT_FUNC( PFNGLGETQUERYOBJECTIVARBPROC, glGetQueryObjectivARB) \
HANDLE_EXT_FUNC( PFNGLGETQUERYOBJECTUIVARBPROC, glGetQueryObjectuivARB) \
#define GL_ARB_occlusion_query_functions \
HANDLE_EXT_FUNC( PFNGLGENQUERIESARBPROC, glGenQueriesARB) \
HANDLE_EXT_FUNC( PFNGLDELETEQUERIESARBPROC, glDeleteQueriesARB) \
HANDLE_EXT_FUNC( PFNGLISQUERYARBPROC, glIsQueryARB) \
HANDLE_EXT_FUNC( PFNGLBEGINQUERYARBPROC, glBeginQueryARB) \
HANDLE_EXT_FUNC( PFNGLENDQUERYARBPROC, glEndQueryARB) \
HANDLE_EXT_FUNC( PFNGLGETQUERYIVARBPROC, glGetQueryivARB) \
HANDLE_EXT_FUNC( PFNGLGETQUERYOBJECTIVARBPROC, glGetQueryObjectivARB) \
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
#define GL_EXT_framebuffer_multisample 1
@ -57,6 +61,7 @@
GL_EXT_framebuffer_multisample_functions \
GL_EXT_framebuffer_blit_functions \
GL_ARB_occlusion_query_functions \
GL_ARB_color_buffer_float_functions \
GL_MISSING_FUNCTIONS \
#endif

View file

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

View file

@ -1,9 +1,5 @@
#include "tr_local.h"
#ifndef ARRAY_SIZE
# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
#endif
#define MAX_FBO_COLOR_BUFFERS 8
/*
@ -426,6 +422,18 @@ static void R_FBO_CreateDefaultBuffers(void)
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);
}

View file

@ -501,11 +501,19 @@ static void Upload32( unsigned *data,
GLenum internalFormat = GL_RGB;
float rMax = 0, gMax = 0, bMax = 0;
// Makro - render target
// Makro - no data, this must be a render target
if (!data)
{
internalFormat = GL_RGBA8;
qglTexImage2D (GL_TEXTURE_2D, 0, internalFormat, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
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;
qglTexImage2D (GL_TEXTURE_2D, 0, internalFormat, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
}
GL_CheckErrors();
*format = internalFormat;
*pUploadWidth = width;
@ -777,19 +785,45 @@ done:
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
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,
qboolean mipmap, qboolean allowPicmip, int glWrapClampMode ) {
image_t *image;
qboolean isLightmap = qfalse;
long hash;
if (strlen(name) >= MAX_QPATH ) {
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");
}
image = tr.images[tr.numImages] = ri.Hunk_Alloc( sizeof( image_t ), h_low );
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;
image = R_AllocImage(name, width, height, mipmap, allowPicmip, glWrapClampMode);
// lightmaps are always allocated on TMU 1
if ( qglActiveTextureARB && isLightmap ) {
@ -845,10 +868,6 @@ image_t *R_CreateImage( const char *name, const byte *pic, int width, int height
GL_SelectTexture( 0 );
}
hash = generateHashValue(name);
image->next = hashTable[hash];
hashTable[hash] = image;
return image;
}
@ -1226,12 +1245,12 @@ void R_SetColorMappings( void ) {
// setup the overbright lighting
tr.overbrightBits = r_overBrightBits->integer;
if ( !glConfig.deviceSupportsGamma ) {
if ( !glConfig.deviceSupportsGamma && !glRefConfig.glslOverbright ) {
tr.overbrightBits = 0; // need hardware gamma for overbright
}
// never overbright in windowed mode
if ( !glConfig.isFullscreen )
if ( !glConfig.isFullscreen && !glRefConfig.glslOverbright )
{
tr.overbrightBits = 0;
}
@ -1268,6 +1287,9 @@ void R_SetColorMappings( void ) {
shift = tr.overbrightBits;
if (glRefConfig.glslOverbright)
shift = 0;
for ( i = 0; i < 256; i++ ) {
if ( g == 1 ) {
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);
qglReadPixels( x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer );
qglReadPixels( x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer );
// gamma correct
if ( glConfig.deviceSupportsGamma ) {
@ -430,6 +430,7 @@ RB_TakeScreenshotCmd
*/
const void *RB_TakeScreenshotCmd( const void *data ) {
const screenshotCommand_t *cmd;
fbo_t *fbo = R_FBO_Bind(NULL);
cmd = (const screenshotCommand_t *)data;
@ -437,6 +438,8 @@ const void *RB_TakeScreenshotCmd( const void *data ) {
RB_TakeScreenshotJPEG( cmd->x, cmd->y, cmd->width, cmd->height, cmd->fileName);
else
RB_TakeScreenshot( cmd->x, cmd->y, cmd->width, cmd->height, cmd->fileName);
R_FBO_Bind(fbo);
return (const void *)(cmd + 1);
}
@ -708,14 +711,19 @@ RB_TakeVideoFrameCmd
const void *RB_TakeVideoFrameCmd( const void *data )
{
const videoFrameCommand_t *cmd;
int frameSize;
int i;
int frameSize;
int i;
fbo_t *fbo;
cmd = (const videoFrameCommand_t *)data;
fbo = R_FBO_Bind(NULL);
qglReadPixels( 0, 0, cmd->width, cmd->height, GL_RGBA,
GL_UNSIGNED_BYTE, cmd->captureBuffer );
R_FBO_Bind(fbo);
// gamma correct
if( glConfig.deviceSupportsGamma )
R_GammaCorrect( cmd->captureBuffer, cmd->width * cmd->height * 4 );
@ -1070,12 +1078,16 @@ void R_InitQueries(void)
{
if (!glRefConfig.occlusionQuery)
return;
qglGenQueriesARB(ARRAY_SIZE(tr.sunFlareQuery), tr.sunFlareQuery);
}
void R_ShutDownQueries(void)
{
if (!glRefConfig.occlusionQuery)
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))
#ifndef ARRAY_SIZE
# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
#endif
// everything that is needed by the backend needs
// to be double buffered to allow it to run in
// parallel on a dual cpu machine
@ -2166,6 +2170,11 @@ typedef struct {
qboolean framebufferBlit;
qboolean framebufferMultisample;
qboolean glslOverbright;
qboolean textureFloat;
qboolean colorBufferFloat;
qboolean occlusionQuery;
// 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 *quarter[2]; // quarter resolution, no zbuffer
fbo_t *tiny[2]; // 1/16 resolution, no zbuffer
int numFBOs;
fbo_t *fbos[1024];
@ -2352,6 +2362,10 @@ typedef struct {
int numSkins;
skin_t *skins[MAX_SKINS];
GLuint sunFlareQuery[2];
int sunFlareQueryIndex;
qboolean sunFlareQueryActive[2];
float sinTable[FUNCTABLE_SIZE];
float squareTable[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);
}
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
@ -186,6 +215,9 @@ static void RB_GodRays(void)
if (dot < cutoff)
return;
if (!RB_UpdateSunFlareVis())
return;
VectorCopy(backEnd.sunFlarePos, pos);
pos[3] = 1.f;
@ -202,8 +234,8 @@ static void RB_GodRays(void)
// viewport dimensions
w = glConfig.vidWidth;
h = glConfig.vidHeight;
w2 = w * 0.5f;
h2 = h * 0.5f;
w2 = glConfig.vidWidth / 2;
h2 = glConfig.vidHeight / 2;
// initialize quarter buffers
{
@ -212,7 +244,7 @@ static void RB_GodRays(void)
RB_SetGL2D_Level(1);
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
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
{
float mul = 1.f;
R_FBO_BindColorBuffer(R_FBO_Bind(tr.fbo.full[0]), 0);
RB_SetGL2D_Level(0);
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);
}
}
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)
{
RB_DrawQuad = NULL;
@ -321,6 +405,12 @@ void RB_FBO_Blit(void)
R_FBO_BindColorBuffer(fbo, 0);
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);
R_FBO_Bind(fbo);
@ -334,7 +424,7 @@ RB_PostProcess
void RB_PostProcess(void)
{
if (!glState.currentFBO)
if (!glState.currentFBO || backEnd.refdef.rdflags & RDF_NOWORLDMODEL)
return;
RB_FBO_Set2D();