Merge branch 'multisamplingbuffers' of https://github.com/dpjudas/zdoom

This commit is contained in:
Christoph Oelckers 2016-07-30 16:35:19 +02:00
commit 124c109e18
7 changed files with 223 additions and 37 deletions

View file

@ -188,7 +188,7 @@ void FGLRenderer::BloomScene()
mBlurShader->BlurVertical(mVBO, blurAmount, sampleCount, level0.HTexture, level0.VFramebuffer, level0.Width, level0.Height); mBlurShader->BlurVertical(mVBO, blurAmount, sampleCount, level0.HTexture, level0.VFramebuffer, level0.Width, level0.Height);
// Add bloom back to scene texture: // Add bloom back to scene texture:
mBuffers->BindSceneFB(); mBuffers->BindSceneTextureFB();
glViewport(0, 0, mOutputViewport.width, mOutputViewport.height); glViewport(0, 0, mOutputViewport.width, mOutputViewport.height);
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD); glBlendEquation(GL_FUNC_ADD);

View file

@ -53,6 +53,7 @@
#include "i_system.h" #include "i_system.h"
#include "doomerrors.h" #include "doomerrors.h"
CVAR(Int, gl_multisample, 1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
CVAR(Bool, gl_renderbuffers, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG); CVAR(Bool, gl_renderbuffers, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
//========================================================================== //==========================================================================
@ -74,10 +75,29 @@ FGLRenderBuffers::FGLRenderBuffers()
FGLRenderBuffers::~FGLRenderBuffers() FGLRenderBuffers::~FGLRenderBuffers()
{ {
Clear(); ClearScene();
ClearHud();
ClearBloom();
} }
void FGLRenderBuffers::Clear() void FGLRenderBuffers::ClearScene()
{
DeleteFrameBuffer(mSceneFB);
DeleteFrameBuffer(mSceneTextureFB);
DeleteRenderBuffer(mSceneMultisample);
DeleteRenderBuffer(mSceneDepthStencil);
DeleteRenderBuffer(mSceneDepth);
DeleteRenderBuffer(mSceneStencil);
DeleteTexture(mSceneTexture);
}
void FGLRenderBuffers::ClearHud()
{
DeleteFrameBuffer(mHudFB);
DeleteTexture(mHudTexture);
}
void FGLRenderBuffers::ClearBloom()
{ {
for (int i = 0; i < NumBloomLevels; i++) for (int i = 0; i < NumBloomLevels; i++)
{ {
@ -88,16 +108,6 @@ void FGLRenderBuffers::Clear()
DeleteTexture(level.VTexture); DeleteTexture(level.VTexture);
level = FGLBloomTextureLevel(); level = FGLBloomTextureLevel();
} }
DeleteFrameBuffer(mSceneFB);
DeleteTexture(mSceneTexture);
DeleteRenderBuffer(mSceneDepthStencil);
DeleteRenderBuffer(mSceneDepth);
DeleteRenderBuffer(mSceneStencil);
DeleteFrameBuffer(mHudFB);
DeleteTexture(mHudTexture);
mWidth = 0;
mHeight = 0;
} }
void FGLRenderBuffers::DeleteTexture(GLuint &handle) void FGLRenderBuffers::DeleteTexture(GLuint &handle)
@ -130,28 +140,80 @@ void FGLRenderBuffers::DeleteFrameBuffer(GLuint &handle)
void FGLRenderBuffers::Setup(int width, int height) void FGLRenderBuffers::Setup(int width, int height)
{ {
if (width <= mWidth && height <= mHeight) int samples = GetCvarSamples();
return;
Clear(); if (width == mWidth && height == mHeight && mSamples != samples)
{
CreateScene(mWidth, mHeight, samples);
mSamples = samples;
}
else if (width > mWidth || height > mHeight)
{
CreateScene(width, height, samples);
CreateHud(width, height);
CreateBloom(width, height);
mWidth = width;
mHeight = height;
mSamples = samples;
}
GLuint hdrFormat = ((gl.flags & RFL_NO_RGBA16F) != 0) ? GL_RGBA8 : GL_RGBA16F; glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
//==========================================================================
//
// Creates the scene buffers
//
//==========================================================================
void FGLRenderBuffers::CreateScene(int width, int height, int samples)
{
ClearScene();
mSceneTexture = Create2DTexture(GetHdrFormat(), width, height);
mSceneTextureFB = CreateFrameBuffer(mSceneTexture);
if (samples > 1)
mSceneMultisample = CreateRenderBuffer(GetHdrFormat(), samples, width, height);
mSceneTexture = Create2DTexture(hdrFormat, width, height);
if ((gl.flags & RFL_NO_DEPTHSTENCIL) != 0) if ((gl.flags & RFL_NO_DEPTHSTENCIL) != 0)
{ {
mSceneDepth = CreateRenderBuffer(GL_DEPTH_COMPONENT24, width, height); mSceneDepth = CreateRenderBuffer(GL_DEPTH_COMPONENT24, samples, width, height);
mSceneStencil = CreateRenderBuffer(GL_STENCIL_INDEX8, width, height); mSceneStencil = CreateRenderBuffer(GL_STENCIL_INDEX8, samples, width, height);
mSceneFB = CreateFrameBuffer(mSceneTexture, mSceneDepth, mSceneStencil); mSceneFB = CreateFrameBuffer(samples > 1 ? mSceneMultisample : mSceneTexture, mSceneDepth, mSceneStencil);
} }
else else
{ {
mSceneDepthStencil = CreateRenderBuffer(GL_DEPTH24_STENCIL8, width, height); mSceneDepthStencil = CreateRenderBuffer(GL_DEPTH24_STENCIL8, samples, width, height);
mSceneFB = CreateFrameBuffer(mSceneTexture, mSceneDepthStencil); mSceneFB = CreateFrameBuffer(samples > 1 ? mSceneMultisample : mSceneTexture, mSceneDepthStencil);
} }
}
mHudTexture = Create2DTexture(hdrFormat, width, height); //==========================================================================
//
// Creates the post-tonemapping-step buffers
//
//==========================================================================
void FGLRenderBuffers::CreateHud(int width, int height)
{
ClearHud();
mHudTexture = Create2DTexture(GetHdrFormat(), width, height);
mHudFB = CreateFrameBuffer(mHudTexture); mHudFB = CreateFrameBuffer(mHudTexture);
}
//==========================================================================
//
// Creates bloom pass working buffers
//
//==========================================================================
void FGLRenderBuffers::CreateBloom(int width, int height)
{
ClearBloom();
int bloomWidth = MAX(width / 2, 1); int bloomWidth = MAX(width / 2, 1);
int bloomHeight = MAX(height / 2, 1); int bloomHeight = MAX(height / 2, 1);
@ -161,22 +223,44 @@ void FGLRenderBuffers::Setup(int width, int height)
level.Width = MAX(bloomWidth / 2, 1); level.Width = MAX(bloomWidth / 2, 1);
level.Height = MAX(bloomHeight / 2, 1); level.Height = MAX(bloomHeight / 2, 1);
level.VTexture = Create2DTexture(hdrFormat, level.Width, level.Height); level.VTexture = Create2DTexture(GetHdrFormat(), level.Width, level.Height);
level.HTexture = Create2DTexture(hdrFormat, level.Width, level.Height); level.HTexture = Create2DTexture(GetHdrFormat(), level.Width, level.Height);
level.VFramebuffer = CreateFrameBuffer(level.VTexture); level.VFramebuffer = CreateFrameBuffer(level.VTexture);
level.HFramebuffer = CreateFrameBuffer(level.HTexture); level.HFramebuffer = CreateFrameBuffer(level.HTexture);
bloomWidth = level.Width; bloomWidth = level.Width;
bloomHeight = level.Height; bloomHeight = level.Height;
} }
}
glActiveTexture(GL_TEXTURE0); //==========================================================================
glBindTexture(GL_TEXTURE_2D, 0); //
glBindRenderbuffer(GL_RENDERBUFFER, 0); // Fallback support for older OpenGL where RGBA16F might not be available
glBindFramebuffer(GL_FRAMEBUFFER, mOutputFB); //
//==========================================================================
mWidth = width; GLuint FGLRenderBuffers::GetHdrFormat()
mHeight = height; {
return ((gl.flags & RFL_NO_RGBA16F) != 0) ? GL_RGBA8 : GL_RGBA16F;
}
//==========================================================================
//
// Converts the CVAR multisample value into a valid level for OpenGL
//
//==========================================================================
int FGLRenderBuffers::GetCvarSamples()
{
int maxSamples = 0;
glGetIntegerv(GL_MAX_SAMPLES, &maxSamples);
int samples = clamp((int)gl_multisample, 0, maxSamples);
int count;
for (count = 0; samples > 0; count++)
samples >>= 1;
return count;
} }
//========================================================================== //==========================================================================
@ -215,6 +299,18 @@ GLuint FGLRenderBuffers::CreateRenderBuffer(GLuint format, int width, int height
return handle; return handle;
} }
GLuint FGLRenderBuffers::CreateRenderBuffer(GLuint format, int samples, int width, int height)
{
if (samples <= 1)
return CreateRenderBuffer(format, width, height);
GLuint handle = 0;
glGenRenderbuffers(1, &handle);
glBindRenderbuffer(GL_RENDERBUFFER, handle);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, format, width, height);
return handle;
}
//========================================================================== //==========================================================================
// //
// Creates a frame buffer // Creates a frame buffer
@ -227,6 +323,7 @@ GLuint FGLRenderBuffers::CreateFrameBuffer(GLuint colorbuffer)
glGenFramebuffers(1, &handle); glGenFramebuffers(1, &handle);
glBindFramebuffer(GL_FRAMEBUFFER, handle); glBindFramebuffer(GL_FRAMEBUFFER, handle);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorbuffer, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorbuffer, 0);
CheckFrameBufferCompleteness();
return handle; return handle;
} }
@ -237,6 +334,7 @@ GLuint FGLRenderBuffers::CreateFrameBuffer(GLuint colorbuffer, GLuint depthstenc
glBindFramebuffer(GL_FRAMEBUFFER, handle); glBindFramebuffer(GL_FRAMEBUFFER, handle);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorbuffer, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorbuffer, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthstencil); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthstencil);
CheckFrameBufferCompleteness();
return handle; return handle;
} }
@ -248,12 +346,59 @@ GLuint FGLRenderBuffers::CreateFrameBuffer(GLuint colorbuffer, GLuint depth, GLu
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorbuffer, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorbuffer, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, stencil); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, stencil);
CheckFrameBufferCompleteness();
return handle; return handle;
} }
//========================================================================== //==========================================================================
// //
// Makes the scene frame buffer active // Verifies that the frame buffer setup is valid
//
//==========================================================================
void FGLRenderBuffers::CheckFrameBufferCompleteness()
{
GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (result == GL_FRAMEBUFFER_COMPLETE)
return;
FString error = "glCheckFramebufferStatus failed: ";
switch (result)
{
default: error.AppendFormat("error code %d", (int)result); break;
case GL_FRAMEBUFFER_UNDEFINED: error << "GL_FRAMEBUFFER_UNDEFINED"; break;
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: error << "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"; break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: error << "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"; break;
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: error << "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER"; break;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: error << "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER"; break;
case GL_FRAMEBUFFER_UNSUPPORTED: error << "GL_FRAMEBUFFER_UNSUPPORTED"; break;
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: error << "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE"; break;
case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS: error << "GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS"; break;
}
I_FatalError(error);
}
//==========================================================================
//
// Resolves the multisample frame buffer by copying it to the scene texture
//
//==========================================================================
void FGLRenderBuffers::BlitSceneToTexture()
{
if (mSamples <= 1)
return;
glBindFramebuffer(GL_READ_FRAMEBUFFER, mSceneFB);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mSceneTextureFB);
glBlitFramebuffer(0, 0, mWidth, mHeight, 0, 0, mWidth, mHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
}
//==========================================================================
//
// Makes the scene frame buffer active (multisample, depth, stecil, etc.)
// //
//========================================================================== //==========================================================================
@ -262,6 +407,17 @@ void FGLRenderBuffers::BindSceneFB()
glBindFramebuffer(GL_FRAMEBUFFER, mSceneFB); glBindFramebuffer(GL_FRAMEBUFFER, mSceneFB);
} }
//==========================================================================
//
// Makes the scene texture frame buffer active (final 2D texture only)
//
//==========================================================================
void FGLRenderBuffers::BindSceneTextureFB()
{
glBindFramebuffer(GL_FRAMEBUFFER, mSceneTextureFB);
}
//========================================================================== //==========================================================================
// //
// Makes the 2D/HUD frame buffer active // Makes the 2D/HUD frame buffer active
@ -273,7 +429,7 @@ void FGLRenderBuffers::BindHudFB()
if (gl_tonemap != 0) if (gl_tonemap != 0)
glBindFramebuffer(GL_FRAMEBUFFER, mHudFB); glBindFramebuffer(GL_FRAMEBUFFER, mHudFB);
else else
glBindFramebuffer(GL_FRAMEBUFFER, mSceneFB); glBindFramebuffer(GL_FRAMEBUFFER, mSceneTextureFB);
} }
//========================================================================== //==========================================================================

View file

@ -21,7 +21,9 @@ public:
~FGLRenderBuffers(); ~FGLRenderBuffers();
void Setup(int width, int height); void Setup(int width, int height);
void BlitSceneToTexture();
void BindSceneFB(); void BindSceneFB();
void BindSceneTextureFB();
void BindHudFB(); void BindHudFB();
void BindOutputFB(); void BindOutputFB();
void BindSceneTexture(int index); void BindSceneTexture(int index);
@ -33,24 +35,37 @@ public:
static bool IsEnabled(); static bool IsEnabled();
private: private:
void Clear(); void ClearScene();
void ClearHud();
void ClearBloom();
void CreateScene(int width, int height, int samples);
void CreateHud(int width, int height);
void CreateBloom(int width, int height);
GLuint Create2DTexture(GLuint format, int width, int height); GLuint Create2DTexture(GLuint format, int width, int height);
GLuint CreateRenderBuffer(GLuint format, int width, int height); GLuint CreateRenderBuffer(GLuint format, int width, int height);
GLuint CreateRenderBuffer(GLuint format, int samples, int width, int height);
GLuint CreateFrameBuffer(GLuint colorbuffer); GLuint CreateFrameBuffer(GLuint colorbuffer);
GLuint CreateFrameBuffer(GLuint colorbuffer, GLuint depthstencil); GLuint CreateFrameBuffer(GLuint colorbuffer, GLuint depthstencil);
GLuint CreateFrameBuffer(GLuint colorbuffer, GLuint depth, GLuint stencil); GLuint CreateFrameBuffer(GLuint colorbuffer, GLuint depth, GLuint stencil);
void CheckFrameBufferCompleteness();
void DeleteTexture(GLuint &handle); void DeleteTexture(GLuint &handle);
void DeleteRenderBuffer(GLuint &handle); void DeleteRenderBuffer(GLuint &handle);
void DeleteFrameBuffer(GLuint &handle); void DeleteFrameBuffer(GLuint &handle);
int GetCvarSamples();
GLuint GetHdrFormat();
int mWidth = 0; int mWidth = 0;
int mHeight = 0; int mHeight = 0;
int mSamples = 0;
GLuint mSceneTexture = 0; GLuint mSceneTexture = 0;
GLuint mSceneMultisample = 0;
GLuint mSceneDepthStencil = 0; GLuint mSceneDepthStencil = 0;
GLuint mSceneDepth = 0; GLuint mSceneDepth = 0;
GLuint mSceneStencil = 0; GLuint mSceneStencil = 0;
GLuint mSceneFB = 0; GLuint mSceneFB = 0;
GLuint mSceneTextureFB = 0;
GLuint mHudTexture = 0; GLuint mHudTexture = 0;
GLuint mHudFB = 0; GLuint mHudFB = 0;
GLuint mOutputFB = 0; GLuint mOutputFB = 0;

View file

@ -868,6 +868,7 @@ sector_t * FGLRenderer::RenderViewpoint (AActor * camera, GL_IRECT * bounds, flo
if (mainview) EndDrawScene(retval); // do not call this for camera textures. if (mainview) EndDrawScene(retval); // do not call this for camera textures.
if (toscreen) if (toscreen)
{ {
if (FGLRenderBuffers::IsEnabled()) mBuffers->BlitSceneToTexture();
BloomScene(); BloomScene();
TonemapScene(); TonemapScene();
} }

View file

@ -41,9 +41,10 @@ EXTERN_CVAR(Bool, gl_seamless)
EXTERN_CVAR(Float, gl_mask_threshold) EXTERN_CVAR(Float, gl_mask_threshold)
EXTERN_CVAR(Float, gl_mask_sprite_threshold) EXTERN_CVAR(Float, gl_mask_sprite_threshold)
EXTERN_CVAR(Bool, gl_renderbuffers); EXTERN_CVAR(Bool, gl_renderbuffers)
EXTERN_CVAR(Int, gl_multisample)
EXTERN_CVAR(Bool, gl_bloom); EXTERN_CVAR(Bool, gl_bloom)
EXTERN_CVAR(Float, gl_bloom_amount) EXTERN_CVAR(Float, gl_bloom_amount)
EXTERN_CVAR(Int, gl_bloom_kernel_size) EXTERN_CVAR(Int, gl_bloom_kernel_size)
EXTERN_CVAR(Int, gl_tonemap) EXTERN_CVAR(Int, gl_tonemap)

View file

@ -2618,6 +2618,7 @@ GLPREFMNU_AMBLIGHT = "Ambient light level";
GLPREFMNU_RENDERQUALITY = "Rendering quality"; GLPREFMNU_RENDERQUALITY = "Rendering quality";
GLPREFMNU_VRMODE = "Stereo 3D VR"; GLPREFMNU_VRMODE = "Stereo 3D VR";
GLPREFMNU_VRQUADSTEREO = "Enable Quad Stereo"; GLPREFMNU_VRQUADSTEREO = "Enable Quad Stereo";
GLPREFMNU_MULTISAMPLE = "Multisample";
GLPREFMNU_TONEMAP = "Tonemap Mode"; GLPREFMNU_TONEMAP = "Tonemap Mode";
GLPREFMNU_BLOOM = "Bloom effect"; GLPREFMNU_BLOOM = "Bloom effect";
@ -2644,6 +2645,7 @@ OPTVAL_2X = "2x";
OPTVAL_4X = "4x"; OPTVAL_4X = "4x";
OPTVAL_8X = "8x"; OPTVAL_8X = "8x";
OPTVAL_16X = "16x"; OPTVAL_16X = "16x";
OPTVAL_32X = "32x";
OPTVAL_USEASPALETTE = "Use as palette"; OPTVAL_USEASPALETTE = "Use as palette";
OPTVAL_BLEND = "Blend"; OPTVAL_BLEND = "Blend";
OPTVAL_STANDARD = "Standard"; OPTVAL_STANDARD = "Standard";

View file

@ -63,6 +63,16 @@ OptionValue "Anisotropy"
16, "$OPTVAL_16X" 16, "$OPTVAL_16X"
} }
OptionValue "Multisample"
{
1, "$OPTVAL_OFF"
2, "$OPTVAL_2X"
4, "$OPTVAL_4X"
8, "$OPTVAL_8X"
16, "$OPTVAL_16X"
32, "$OPTVAL_32X"
}
OptionValue "Colormaps" OptionValue "Colormaps"
{ {
0, "$OPTVAL_USEASPALETTE" 0, "$OPTVAL_USEASPALETTE"
@ -207,6 +217,7 @@ OptionMenu "GLPrefOptions"
Option "$GLPREFMNU_RENDERQUALITY", gl_render_precise, "Precision" Option "$GLPREFMNU_RENDERQUALITY", gl_render_precise, "Precision"
Option "$GLPREFMNU_VRMODE", vr_mode, "VRMode" Option "$GLPREFMNU_VRMODE", vr_mode, "VRMode"
Option "$GLPREFMNU_VRQUADSTEREO", vr_enable_quadbuffered, "OnOff" Option "$GLPREFMNU_VRQUADSTEREO", vr_enable_quadbuffered, "OnOff"
Option "$GLPREFMNU_MULTISAMPLE", gl_multisample, "Multisample"
Option "$GLPREFMNU_TONEMAP", gl_tonemap, "TonemapModes" Option "$GLPREFMNU_TONEMAP", gl_tonemap, "TonemapModes"
Option "$GLPREFMNU_BLOOM", gl_bloom, "OnOff" Option "$GLPREFMNU_BLOOM", gl_bloom, "OnOff"
} }