mirror of
https://github.com/ReactionQuake3/reaction.git
synced 2025-01-23 01:50:41 +00:00
Multisampling
This commit is contained in:
parent
14ffe063ea
commit
36bf6c2d9e
3 changed files with 231 additions and 47 deletions
|
@ -4,22 +4,60 @@
|
|||
# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
|
||||
#endif
|
||||
|
||||
#define MAX_FBO_COLOR_BUFFERS 8
|
||||
|
||||
/*
|
||||
===============
|
||||
Render buffer
|
||||
Can be either a zbuffer, a stencil buffer or a multisampled color buffer
|
||||
===============
|
||||
*/
|
||||
|
||||
typedef struct fboRenderBuffer_s {
|
||||
GLuint id;
|
||||
int internalFormat;
|
||||
|
||||
int width;
|
||||
int height;
|
||||
qboolean msaa;
|
||||
} fboRenderBuffer_t;
|
||||
|
||||
#define MAX_FBO_COLOR_BUFFERS 8
|
||||
typedef fboRenderBuffer_t fboZBuffer_t;
|
||||
typedef fboRenderBuffer_t fboStencilBuffer_t;
|
||||
|
||||
/*
|
||||
===============
|
||||
Color buffer
|
||||
|
||||
If anti-aliased we'll have a texture, a render buffer
|
||||
and two frame buffers needed for the MSAA resolve.
|
||||
|
||||
Otherwise, only the texture is initialized.
|
||||
===============
|
||||
*/
|
||||
|
||||
typedef struct fboColorBuffer_s {
|
||||
fboRenderBuffer_t *buf;
|
||||
image_t *tex;
|
||||
GLuint fboResolve[2];
|
||||
qboolean dirty;
|
||||
} fboColorBuffer_t;
|
||||
|
||||
/*
|
||||
===============
|
||||
Frame buffer
|
||||
|
||||
Has one or more color buffers, an optional zbuffer
|
||||
and an optional stencil buffer
|
||||
===============
|
||||
*/
|
||||
|
||||
typedef struct fbo_s {
|
||||
GLuint id;
|
||||
|
||||
int numColorBufs;
|
||||
|
||||
image_t* color[MAX_FBO_COLOR_BUFFERS];
|
||||
fboColorBuffer_t* color[MAX_FBO_COLOR_BUFFERS];
|
||||
fboZBuffer_t* depth;
|
||||
fboStencilBuffer_t* stencil;
|
||||
|
||||
|
@ -32,7 +70,14 @@ void R_FBO_InitRenderBuffer(fboRenderBuffer_t* buf)
|
|||
buf->id = 0;
|
||||
qglGenRenderbuffersEXT(1, &buf->id);
|
||||
qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, buf->id);
|
||||
qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, buf->internalFormat, buf->width, buf->height);
|
||||
if (buf->msaa)
|
||||
{
|
||||
qglRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, tr.fbo.maxSamples, buf->internalFormat, buf->width, buf->height);
|
||||
}
|
||||
else
|
||||
{
|
||||
qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, buf->internalFormat, buf->width, buf->height);
|
||||
}
|
||||
qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
|
||||
}
|
||||
|
||||
|
@ -45,7 +90,7 @@ void R_FBO_ReleaseRenderBuffer(fboRenderBuffer_t* buf)
|
|||
buf->id = 0;
|
||||
}
|
||||
|
||||
fboRenderBuffer_t* R_FBO_CreateRenderBuffer(int width, int height, int pixelformat)
|
||||
fboRenderBuffer_t *R_FBO_CreateRenderBuffer(int width, int height, int pixelformat, qboolean msaa)
|
||||
{
|
||||
fboRenderBuffer_t* ret = NULL;
|
||||
if (tr.fbo.numRenderBuffers >= ARRAY_SIZE(tr.fbo.renderBuffers))
|
||||
|
@ -60,6 +105,7 @@ fboRenderBuffer_t* R_FBO_CreateRenderBuffer(int width, int height, int pixelform
|
|||
ret->width = width;
|
||||
ret->height = height;
|
||||
ret->internalFormat = pixelformat;
|
||||
ret->msaa = (msaa && tr.fbo.maxSamples > 1);
|
||||
|
||||
R_FBO_InitRenderBuffer(ret);
|
||||
|
||||
|
@ -68,38 +114,6 @@ fboRenderBuffer_t* R_FBO_CreateRenderBuffer(int width, int height, int pixelform
|
|||
return ret;
|
||||
}
|
||||
|
||||
fboZBuffer_t* R_FBO_CreateZBuffer(int width, int height)
|
||||
{
|
||||
return R_FBO_CreateRenderBuffer(width, height, GL_DEPTH_COMPONENT24);
|
||||
}
|
||||
|
||||
void R_FBO_Init(fbo_t* fbo)
|
||||
{
|
||||
memset(fbo, 0, sizeof(*fbo));
|
||||
qglGenFramebuffersEXT(1, &fbo->id);
|
||||
}
|
||||
|
||||
void R_FBO_Release(fbo_t* fbo)
|
||||
{
|
||||
if (fbo->id == 0)
|
||||
return;
|
||||
|
||||
qglDeleteFramebuffersEXT(1, &fbo->id);
|
||||
fbo->id = 0;
|
||||
}
|
||||
|
||||
void R_FBO_AddColorBuffer(fbo_t* fbo, image_t* image)
|
||||
{
|
||||
if (fbo->numColorBufs >= ARRAY_SIZE(fbo->color))
|
||||
{
|
||||
ri.Error(ERR_FATAL, "Max FBO color buffers exceeded.\n");
|
||||
return;
|
||||
}
|
||||
fbo->color[fbo->numColorBufs++] = image;
|
||||
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->id);
|
||||
qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, (GLenum)(GL_COLOR_ATTACHMENT0_EXT + fbo->numColorBufs - 1), GL_TEXTURE_2D, image->texnum, 0);
|
||||
}
|
||||
|
||||
qboolean R_FBO_Check()
|
||||
{
|
||||
GLenum status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
|
||||
|
@ -137,6 +151,10 @@ qboolean R_FBO_Check()
|
|||
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
|
||||
msg = "incomplete read buffer";
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT:
|
||||
msg = "mismatched multisample settings";
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
|
||||
msg = "unsupported";
|
||||
|
@ -147,11 +165,106 @@ qboolean R_FBO_Check()
|
|||
break;
|
||||
}
|
||||
|
||||
ri.Error(ERR_FATAL, "Bad framebuffer setup for '%s': %s\n", glState.currentFBO->name, msg);
|
||||
ri.Error(ERR_FATAL, "Framebuffer setup error: %s\n", msg);
|
||||
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
fboColorBuffer_t *R_FBO_CreateColorBuffer(const char* name, int width, int height, qboolean msaa, qboolean mipmap, int clamp)
|
||||
{
|
||||
if (tr.fbo.numColorBuffers>= ARRAY_SIZE(tr.fbo.colorBuffers))
|
||||
{
|
||||
ri.Error(ERR_FATAL, "Too many FBO color buffers\n");
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
qboolean realmsaa = msaa && tr.fbo.maxSamples > 1;
|
||||
image_t *texture = R_CreateImage(name, NULL, width, height, mipmap, qfalse, clamp);
|
||||
fboRenderBuffer_t *buf = realmsaa ? R_FBO_CreateRenderBuffer(width, height, texture->internalFormat, qtrue) : NULL;
|
||||
fboColorBuffer_t *ret = ri.Hunk_Alloc(sizeof(*ret), h_low);
|
||||
|
||||
Com_Memset(ret, 0, sizeof(*ret));
|
||||
|
||||
ret->buf = buf;
|
||||
ret->tex = texture;
|
||||
ret->dirty = qfalse;
|
||||
|
||||
if (realmsaa)
|
||||
{
|
||||
qglGenFramebuffersEXT(2, ret->fboResolve);
|
||||
|
||||
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ret->fboResolve[0]);
|
||||
qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, ret->buf->id);
|
||||
R_FBO_Check();
|
||||
|
||||
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ret->fboResolve[1]);
|
||||
qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, ret->tex->texnum, 0);
|
||||
R_FBO_Check();
|
||||
|
||||
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret->fboResolve[0] = ret->fboResolve[1] = 0;
|
||||
}
|
||||
|
||||
tr.fbo.colorBuffers[tr.fbo.numColorBuffers++] = ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
void R_FBO_ReleaseColorBuffer(fboColorBuffer_t* color)
|
||||
{
|
||||
if (color->buf)
|
||||
{
|
||||
qglDeleteFramebuffersEXT(2, color->fboResolve);
|
||||
}
|
||||
}
|
||||
|
||||
fboZBuffer_t *R_FBO_CreateZBuffer(int width, int height, qboolean msaa)
|
||||
{
|
||||
return R_FBO_CreateRenderBuffer(width, height, GL_DEPTH_COMPONENT24, msaa);
|
||||
}
|
||||
|
||||
void R_FBO_Init(fbo_t* fbo)
|
||||
{
|
||||
memset(fbo, 0, sizeof(*fbo));
|
||||
qglGenFramebuffersEXT(1, &fbo->id);
|
||||
}
|
||||
|
||||
void R_FBO_Release(fbo_t* fbo)
|
||||
{
|
||||
if (fbo->id == 0)
|
||||
return;
|
||||
|
||||
qglDeleteFramebuffersEXT(1, &fbo->id);
|
||||
fbo->id = 0;
|
||||
}
|
||||
|
||||
void R_FBO_AddColorBuffer(fbo_t* fbo, fboColorBuffer_t* color)
|
||||
{
|
||||
GLenum attach;
|
||||
if (fbo->numColorBufs >= ARRAY_SIZE(fbo->color))
|
||||
{
|
||||
ri.Error(ERR_FATAL, "Max FBO color buffers exceeded.\n");
|
||||
return;
|
||||
}
|
||||
fbo->color[fbo->numColorBufs++] = color;
|
||||
|
||||
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->id);
|
||||
attach = GL_COLOR_ATTACHMENT0_EXT + fbo->numColorBufs - 1;
|
||||
if (color->buf)
|
||||
{
|
||||
qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, attach, GL_RENDERBUFFER_EXT, color->buf->id);
|
||||
}
|
||||
else
|
||||
{
|
||||
qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attach, GL_TEXTURE_2D, color->tex->texnum, 0);
|
||||
}
|
||||
}
|
||||
|
||||
fbo_t* R_FBO_Bind(fbo_t* fbo)
|
||||
{
|
||||
fbo_t* old = glState.currentFBO;
|
||||
|
@ -170,6 +283,13 @@ fbo_t* R_FBO_Bind(fbo_t* fbo)
|
|||
|
||||
if (fbo)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i<fbo->numColorBufs; ++i)
|
||||
{
|
||||
fboColorBuffer_t* color = fbo->color[i];
|
||||
color->dirty = (color->buf != NULL);
|
||||
}
|
||||
|
||||
if (1)
|
||||
R_FBO_Check();
|
||||
}
|
||||
|
@ -179,10 +299,35 @@ fbo_t* R_FBO_Bind(fbo_t* fbo)
|
|||
|
||||
void R_FBO_BindColorBuffer(fbo_t* fbo, int index)
|
||||
{
|
||||
GL_Bind(fbo->color[index]);
|
||||
fboColorBuffer_t* color = fbo->color[index];
|
||||
if (color->dirty)
|
||||
{
|
||||
color->dirty = qfalse;
|
||||
|
||||
// resolve
|
||||
if (color->buf)
|
||||
{
|
||||
int id;
|
||||
int width = color->buf->width;
|
||||
int height = color->buf->height;
|
||||
|
||||
qglBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, color->fboResolve[0]);
|
||||
qglBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, color->fboResolve[1]);
|
||||
qglBlitFramebufferEXT(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||
|
||||
if (glState.currentFBO)
|
||||
id = glState.currentFBO->id;
|
||||
else
|
||||
id = 0;
|
||||
|
||||
qglBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, id);
|
||||
qglBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, id);
|
||||
}
|
||||
}
|
||||
GL_Bind(color->tex);
|
||||
}
|
||||
|
||||
fbo_t* R_FBO_CreateEx(const char* name, int numColorBuffers, image_t** colorBuffers, fboZBuffer_t* depth, fboStencilBuffer_t* stencil)
|
||||
fbo_t* R_FBO_CreateEx(const char* name, int numColorBuffers, fboColorBuffer_t** colorBuffers, fboZBuffer_t* depth, fboStencilBuffer_t* stencil)
|
||||
{
|
||||
fbo_t* fbo = NULL;
|
||||
|
||||
|
@ -221,45 +366,75 @@ fbo_t* R_FBO_CreateEx(const char* name, int numColorBuffers, image_t** colorBuff
|
|||
return fbo;
|
||||
}
|
||||
|
||||
fbo_t* R_FBO_CreateSimple(const char* name, image_t* color, fboZBuffer_t* depth, fboStencilBuffer_t* stencil)
|
||||
fbo_t* R_FBO_CreateSimple(const char* name, fboColorBuffer_t* color, fboZBuffer_t* depth, fboStencilBuffer_t* stencil)
|
||||
{
|
||||
return R_FBO_CreateEx(name, color != NULL, &color, depth, stencil);
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
R_InitFBOs
|
||||
===============
|
||||
*/
|
||||
|
||||
void R_InitFBOs(void)
|
||||
{
|
||||
qboolean msaa;
|
||||
if (!glRefConfig.framebufferObject)
|
||||
return;
|
||||
|
||||
ri.Printf(PRINT_ALL, "------- R_InitFBOs -------\n");
|
||||
|
||||
if (glRefConfig.framebufferMultisample && glRefConfig.framebufferBlit)
|
||||
{
|
||||
GLint maxSupported = 0;
|
||||
qglGetIntegerv(GL_MAX_SAMPLES_EXT, &maxSupported);
|
||||
tr.fbo.maxSamples = maxSupported < r_ext_multisample->integer ? maxSupported : r_ext_multisample->integer;
|
||||
if (tr.fbo.maxSamples < 2)
|
||||
tr.fbo.maxSamples = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
tr.fbo.maxSamples = 0;
|
||||
}
|
||||
|
||||
Com_Printf("Samples: %d\n", tr.fbo.maxSamples);
|
||||
msaa = tr.fbo.maxSamples > 1;
|
||||
|
||||
tr.fbo.full[0] = R_FBO_CreateSimple(
|
||||
"main",
|
||||
R_CreateImage("*framebuffer", NULL, glConfig.vidWidth, glConfig.vidHeight, qfalse, qfalse, GL_CLAMP_TO_EDGE),
|
||||
R_FBO_CreateZBuffer(glConfig.vidWidth, glConfig.vidHeight),
|
||||
R_FBO_CreateColorBuffer("*framebuffer0", glConfig.vidWidth, glConfig.vidHeight, msaa, qfalse, GL_CLAMP_TO_EDGE),
|
||||
R_FBO_CreateZBuffer(glConfig.vidWidth, glConfig.vidHeight, msaa),
|
||||
NULL);
|
||||
|
||||
tr.fbo.full[1] = R_FBO_CreateSimple(
|
||||
"postprocess",
|
||||
R_CreateImage("*framebuffer", NULL, glConfig.vidWidth, glConfig.vidHeight, qfalse, qfalse, GL_CLAMP_TO_EDGE),
|
||||
R_FBO_CreateColorBuffer("*framebuffer1", glConfig.vidWidth, glConfig.vidHeight, msaa, qfalse, GL_CLAMP_TO_EDGE),
|
||||
tr.fbo.full[0]->depth,
|
||||
NULL);
|
||||
|
||||
tr.fbo.quarter[0] = R_FBO_CreateSimple(
|
||||
"quarter0",
|
||||
R_CreateImage("*quarterBuffer0", NULL, glConfig.vidWidth/2, glConfig.vidHeight/2, qfalse, qfalse, GL_CLAMP_TO_EDGE),
|
||||
R_FBO_CreateColorBuffer("*quarterBuffer0", glConfig.vidWidth/2, glConfig.vidHeight/2, qfalse, qfalse, GL_CLAMP_TO_EDGE),
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
tr.fbo.quarter[1] = R_FBO_CreateSimple(
|
||||
"quarter1",
|
||||
R_CreateImage("*quarterBuffer1", NULL, glConfig.vidWidth/2, glConfig.vidHeight/2, qfalse, qfalse, GL_CLAMP_TO_EDGE),
|
||||
R_FBO_CreateColorBuffer("*quarterBuffer1", glConfig.vidWidth/2, glConfig.vidHeight/2, qfalse, qfalse, GL_CLAMP_TO_EDGE),
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
ri.Printf(PRINT_DEVELOPER, "Created %d FBOs\n", tr.fbo.numFBOs);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
R_ShutDownFBOs
|
||||
===============
|
||||
*/
|
||||
|
||||
void R_ShutDownFBOs(void)
|
||||
{
|
||||
if (!glRefConfig.framebufferObject)
|
||||
|
@ -272,6 +447,9 @@ void R_ShutDownFBOs(void)
|
|||
while (tr.fbo.numRenderBuffers>0)
|
||||
R_FBO_ReleaseRenderBuffer(tr.fbo.renderBuffers[--tr.fbo.numRenderBuffers]);
|
||||
|
||||
while (tr.fbo.numColorBuffers>0)
|
||||
R_FBO_ReleaseColorBuffer(tr.fbo.colorBuffers[--tr.fbo.numColorBuffers]);
|
||||
|
||||
while (tr.fbo.numFBOs>0)
|
||||
R_FBO_Release(tr.fbo.fbos[--tr.fbo.numFBOs]);
|
||||
}
|
||||
|
|
|
@ -153,8 +153,7 @@ typedef struct IBO_s
|
|||
} IBO_t;
|
||||
|
||||
typedef struct fboRenderBuffer_s fboRenderBuffer_t;
|
||||
typedef fboRenderBuffer_t fboZBuffer_t;
|
||||
typedef fboRenderBuffer_t fboStencilBuffer_t;
|
||||
typedef struct fboColorBuffer_s fboColorBuffer_t;
|
||||
typedef struct fbo_s fbo_t;
|
||||
|
||||
fbo_t *R_FBO_Bind(fbo_t* fbo);
|
||||
|
@ -2224,6 +2223,8 @@ typedef struct {
|
|||
} backEndState_t;
|
||||
|
||||
typedef struct {
|
||||
int maxSamples;
|
||||
|
||||
fbo_t *full[2]; // full resolution, shared zbuffer
|
||||
fbo_t *quarter[2]; // quarter resolution, no zbuffer
|
||||
|
||||
|
@ -2232,6 +2233,9 @@ typedef struct {
|
|||
|
||||
int numRenderBuffers;
|
||||
fboRenderBuffer_t *renderBuffers[1024];
|
||||
|
||||
int numColorBuffers;
|
||||
fboColorBuffer_t *colorBuffers[1024];
|
||||
} fboState_t;
|
||||
|
||||
/*
|
||||
|
|
|
@ -425,6 +425,8 @@ static int GLimp_SetMode(int mode, qboolean fullscreen, qboolean noborder)
|
|||
depthbits = r_depthbits->value;
|
||||
stencilbits = r_stencilbits->value;
|
||||
samples = r_ext_multisample->value;
|
||||
if (r_ext_framebuffer_object->integer)
|
||||
samples = 0;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue