searching for valid sample counts for MSAA in GL2 and GL3 instead of failing

This commit is contained in:
myT 2019-12-26 16:24:22 +01:00
parent a89a2e3ead
commit 9cb02a32bf
4 changed files with 88 additions and 63 deletions

View file

@ -83,6 +83,8 @@ add: r_mapBrightness now works on q3map2's external lightmap atlas images
add: the renderer can now batch surfaces with different (but sufficiently similar) shaders
this new optimization works with the output of "Frozen Sand Particle Studio"
chg: searching for valid sample counts for MSAA in GL2 and GL3 instead of failing right away
add: /modellist /skinlist /imagelist /shaderlist can now filter results with pattern matching
chg: SSE2 instruction set support is now required

View file

@ -51,6 +51,9 @@ static void RB_FogPass();
static void GAL_Begin2D();
static GLint GetTexEnv( texEnv_t texEnv );
void GL_GetRenderTargetFormat( GLenum* internalFormat, GLenum* format, GLenum* type, int cnq3Format );
void GL_CreateColorRenderBufferStorageMS( int* samples );
struct GLSL_Program {
GLuint p; // linked program
@ -334,12 +337,12 @@ static unsigned int frameBufferReadIndex = 0; // read this for the latest color/
static qbool frameBufferMultiSampling = qfalse;
#define CASE( x ) case x: return #x
#define GL( call ) call; GL2_CheckError( #call, __FUNCTION__, __FILE__, __LINE__ )
static const char* GL2_GetErrorString( GLenum ec )
{
#define CASE( x ) case x: return #x
switch ( ec )
{
CASE( GL_NO_ERROR );
@ -352,6 +355,7 @@ static const char* GL2_GetErrorString( GLenum ec )
CASE( GL_STACK_OVERFLOW );
default: return "?";
}
#undef CASE
}
@ -377,53 +381,6 @@ static void GL2_CheckError( const char* call, const char* function, const char*
}
static const char* GL2_GetFBOStatusString( GLenum status )
{
switch ( status )
{
CASE( GL_FRAMEBUFFER_COMPLETE );
CASE( GL_FRAMEBUFFER_UNDEFINED );
CASE( GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT );
CASE( GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT );
CASE( GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER );
CASE( GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER );
CASE( GL_FRAMEBUFFER_UNSUPPORTED );
CASE( GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE );
CASE( GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS );
default: return "?";
}
}
#undef CASE
void GL_GetRenderTargetFormat( GLenum* internalFormat, GLenum* format, GLenum* type, int cnq3Format )
{
switch( cnq3Format )
{
case RTCF_R10G10B10A2:
*internalFormat = GL_RGB10_A2;
*format = GL_BGRA;
*type = GL_UNSIGNED_INT_2_10_10_10_REV;
break;
case RTCF_R16G16B16A16:
*internalFormat = GL_RGBA16;
*format = GL_BGRA;
*type = GL_UNSIGNED_SHORT;
break;
case RTCF_R8G8B8A8:
default:
*internalFormat = GL_RGBA8;
*format = GL_BGRA;
*type = GL_UNSIGNED_BYTE;
break;
}
}
static qbool GL2_FBO_CreateSS( FrameBuffer& fb, qbool depthStencil )
{
while ( glGetError() != GL_NO_ERROR ) {} // clear the error queue
@ -454,8 +411,7 @@ static qbool GL2_FBO_CreateSS( FrameBuffer& fb, qbool depthStencil )
const GLenum fboStatus = glCheckFramebufferStatus( GL_FRAMEBUFFER );
if ( fboStatus != GL_FRAMEBUFFER_COMPLETE )
{
ri.Printf( PRINT_ERROR, "Failed to create FBO (status 0x%X, error 0x%X)\n", (unsigned int)fboStatus, (unsigned int)glGetError() );
ri.Printf( PRINT_ERROR, "FBO status string: %s\n", GL2_GetFBOStatusString(fboStatus) );
ri.Error( ERR_FATAL, "Failed to create FBO (status 0x%X, error 0x%X)\n", (unsigned int)fboStatus, (unsigned int)glGetError() );
return qfalse;
}
@ -474,16 +430,15 @@ static qbool GL2_FBO_CreateMS( FrameBuffer& fb )
GL(glGenFramebuffers( 1, &fb.fbo ));
GL(glBindFramebuffer( GL_FRAMEBUFFER, fb.fbo ));
GLenum internalFormat, format, type;
GL_GetRenderTargetFormat( &internalFormat, &format, &type, r_rtColorFormat->integer );
int sampleCount = 0;
GL(glGenRenderbuffers( 1, &fb.color ));
GL(glBindRenderbuffer( GL_RENDERBUFFER, fb.color ));
GL(glRenderbufferStorageMultisample( GL_RENDERBUFFER, r_msaa->integer, internalFormat, glConfig.vidWidth, glConfig.vidHeight ));
GL_CreateColorRenderBufferStorageMS( &sampleCount );
GL(glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, fb.color ));
GL(glGenRenderbuffers( 1, &fb.depthStencil ));
GL(glBindRenderbuffer( GL_RENDERBUFFER, fb.depthStencil ));
GL(glRenderbufferStorageMultisample( GL_RENDERBUFFER, r_msaa->integer, GL_DEPTH24_STENCIL8, glConfig.vidWidth, glConfig.vidHeight ));
GL(glRenderbufferStorageMultisample( GL_RENDERBUFFER, sampleCount, GL_DEPTH24_STENCIL8, glConfig.vidWidth, glConfig.vidHeight ));
GL(glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fb.color ));
GL(glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fb.depthStencil ));
@ -491,8 +446,7 @@ static qbool GL2_FBO_CreateMS( FrameBuffer& fb )
const GLenum fboStatus = glCheckFramebufferStatus( GL_FRAMEBUFFER );
if ( fboStatus != GL_FRAMEBUFFER_COMPLETE )
{
ri.Printf( PRINT_ERROR, "Failed to create FBO (status 0x%X, error 0x%X)\n", (unsigned int)fboStatus, (unsigned int)glGetError() );
ri.Printf( PRINT_ERROR, "FBO status string: %s\n", GL2_GetFBOStatusString(fboStatus) );
ri.Error( ERR_FATAL, "Failed to create FBO (status 0x%X, error 0x%X)\n", (unsigned int)fboStatus, (unsigned int)glGetError() );
return qfalse;
}
@ -500,6 +454,8 @@ static qbool GL2_FBO_CreateMS( FrameBuffer& fb )
fb.multiSampled = qtrue;
fb.hasDepthStencil = qtrue;
ri.Printf( PRINT_ALL, "MSAA: %d samples requested, %d selected\n", r_msaa->integer, sampleCount );
return qtrue;
}
@ -507,7 +463,7 @@ static qbool GL2_FBO_CreateMS( FrameBuffer& fb )
static qbool GL2_FBO_Init()
{
const int msaa = r_msaa->integer;
const qbool enable = msaa >= 2 && msaa <= 16;
const qbool enable = msaa >= 2;
frameBufferMultiSampling = enable;
if ( !enable )

View file

@ -650,6 +650,72 @@ static const char* downSample_cs =
" imageStore(dstTex, dstTC, r);\n"
"}\n";
void GL_GetRenderTargetFormat(GLenum* internalFormat, GLenum* format, GLenum* type, int cnq3Format)
{
switch(cnq3Format)
{
case RTCF_R10G10B10A2:
*internalFormat = GL_RGB10_A2;
*format = GL_BGRA;
*type = GL_UNSIGNED_INT_2_10_10_10_REV;
break;
case RTCF_R16G16B16A16:
*internalFormat = GL_RGBA16;
*format = GL_BGRA;
*type = GL_UNSIGNED_SHORT;
break;
case RTCF_R8G8B8A8:
default:
*internalFormat = GL_RGBA8;
*format = GL_BGRA;
*type = GL_UNSIGNED_BYTE;
break;
}
}
void GL_CreateColorRenderBufferStorageMS(int* samples)
{
GLenum internalFormat, format, type;
GL_GetRenderTargetFormat(&internalFormat, &format, &type, r_rtColorFormat->integer);
int sampleCount = r_msaa->integer;
while(glGetError() != GL_NO_ERROR) {} // clear the error queue
if(GLEW_VERSION_4_2 || GLEW_ARB_internalformat_query)
{
GLint maxSampleCount = 0;
glGetInternalformativ(GL_RENDERBUFFER, internalFormat, GL_SAMPLES, 1, &maxSampleCount);
if(glGetError() == GL_NO_ERROR)
{
sampleCount = min(sampleCount, (int)maxSampleCount);
}
}
GLenum errorCode = GL_NO_ERROR;
for(;;)
{
// @NOTE: when the sample count is invalid, the error code is GL_INVALID_OPERATION
glRenderbufferStorageMultisample(GL_RENDERBUFFER, sampleCount, internalFormat, glConfig.vidWidth, glConfig.vidHeight);
errorCode = glGetError();
if(errorCode == GL_NO_ERROR || sampleCount == 0)
{
break;
}
--sampleCount;
}
if(errorCode != GL_NO_ERROR)
{
ri.Error(ERR_FATAL, "Failed to create multi-sampled render buffer storage (error 0x%X)\n", (unsigned int)errorCode);
}
*samples = sampleCount;
}
#if defined(_WIN32)
static void AllocatePinnedMemory(ArrayBuffer* buffer)
@ -879,17 +945,16 @@ static void FBO_CreateMS(FrameBuffer* fb, const char* name)
glGenFramebuffers(1, &fb->fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fb->fbo);
GLenum internalFormat, format, type;
GL_GetRenderTargetFormat(&internalFormat, &format, &type, r_rtColorFormat->integer);
int sampleCount = 0;
glGenRenderbuffers(1, &fb->color);
glBindRenderbuffer(GL_RENDERBUFFER, fb->color);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, r_msaa->integer, internalFormat, glConfig.vidWidth, glConfig.vidHeight);
GL_CreateColorRenderBufferStorageMS(&sampleCount);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, fb->color);
SetDebugName(GL_RENDERBUFFER, fb->color, va("%s color attachment 0", name));
glGenRenderbuffers(1, &fb->depthStencil);
glBindRenderbuffer(GL_RENDERBUFFER, fb->depthStencil);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, r_msaa->integer, GL_DEPTH24_STENCIL8, glConfig.vidWidth, glConfig.vidHeight);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, sampleCount, GL_DEPTH24_STENCIL8, glConfig.vidWidth, glConfig.vidHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fb->depthStencil);
SetDebugName(GL_RENDERBUFFER, fb->depthStencil, va("%s depth/stencil attachment", name));
@ -905,12 +970,14 @@ static void FBO_CreateMS(FrameBuffer* fb, const char* name)
fb->multiSampled = qtrue;
fb->hasDepthStencil = qtrue;
fb->hasColor = qtrue;
ri.Printf(PRINT_ALL, "MSAA: %d samples requested, %d selected\n", r_msaa->integer, sampleCount);
}
static void FBO_Init()
{
const int msaa = r_msaa->integer;
gl.fbMSEnabled = msaa >= 2 && msaa <= 16;
gl.fbMSEnabled = msaa >= 2;
if(gl.fbMSEnabled)
{

View file

@ -367,7 +367,7 @@ static const cvarTableItem_t r_cvars[] =
{ &r_d3d11_syncOffsets, "r_d3d11_syncOffsets", "2", CVAR_ARCHIVE | CVAR_LATCH, CVART_INTEGER, "0", XSTRING(D3D11SO_MAX), help_r_d3d11_syncOffsets },
{ &r_d3d11_maxQueuedFrames, "r_d3d11_maxQueuedFrames", "3", CVAR_ARCHIVE | CVAR_LATCH, CVART_INTEGER, "1", "16", help_r_d3d11_maxQueuedFrames },
{ &r_ext_max_anisotropy, "r_ext_max_anisotropy", "16", CVAR_ARCHIVE | CVAR_LATCH, CVART_INTEGER, "0", "16", help_r_ext_max_anisotropy },
{ &r_msaa, "r_msaa", "0", CVAR_ARCHIVE | CVAR_LATCH, CVART_INTEGER, "0", "16", "anti-aliasing sample count, " S_COLOR_VAL "0" S_COLOR_HELP "=off" },
{ &r_msaa, "r_msaa", "0", CVAR_ARCHIVE | CVAR_LATCH, CVART_INTEGER, "0", "32", "anti-aliasing sample count, " S_COLOR_VAL "0" S_COLOR_HELP "=off" },
{ &r_picmip, "r_picmip", "0", CVAR_ARCHIVE | CVAR_LATCH, CVART_INTEGER, "0", "16", help_r_picmip },
{ &r_roundImagesDown, "r_roundImagesDown", "0", CVAR_ARCHIVE | CVAR_LATCH, CVART_BOOL, NULL, NULL, help_r_roundImagesDown },
{ &r_colorMipLevels, "r_colorMipLevels", "0", CVAR_LATCH, CVART_BOOL, NULL, NULL, "colorizes textures based on their mip level" },