From 1de2691f332dfb2e63ea15ab14d3712d8001d666 Mon Sep 17 00:00:00 2001 From: parax0 Date: Tue, 30 Aug 2016 19:05:28 -0600 Subject: [PATCH] Enabled MSAA --- src/Core/OpenGL/CFramebuffer.cpp | 87 ++++++++++++++++++-------------- src/Core/OpenGL/CFramebuffer.h | 14 +++-- src/Core/OpenGL/CRenderbuffer.h | 41 +++++++++++---- src/Core/Render/CRenderer.cpp | 35 +++++++------ src/Core/Render/CRenderer.h | 1 + src/Core/Resource/CTexture.cpp | 32 ++++++++---- src/Core/Resource/CTexture.h | 17 +++++-- src/Editor/CBasicViewport.cpp | 7 +-- 8 files changed, 146 insertions(+), 88 deletions(-) diff --git a/src/Core/OpenGL/CFramebuffer.cpp b/src/Core/OpenGL/CFramebuffer.cpp index c724d2cb..72584d6a 100644 --- a/src/Core/OpenGL/CFramebuffer.cpp +++ b/src/Core/OpenGL/CFramebuffer.cpp @@ -2,20 +2,22 @@ #include CFramebuffer::CFramebuffer() - : mInitialized(false) + : mpRenderbuffer(nullptr) + , mpTexture(nullptr) , mWidth(0) , mHeight(0) - , mpRenderbuffer(nullptr) - , mpTexture(nullptr) + , mEnableMultisampling(false) + , mInitialized(false) { } CFramebuffer::CFramebuffer(u32 Width, u32 Height) - : mInitialized(false) + : mpRenderbuffer(nullptr) + , mpTexture(nullptr) , mWidth(0) , mHeight(0) - , mpRenderbuffer(nullptr) - , mpTexture(nullptr) + , mEnableMultisampling(false) + , mInitialized(false) { Resize(Width, Height); } @@ -44,30 +46,18 @@ void CFramebuffer::Init() glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer); mpRenderbuffer = new CRenderbuffer(mWidth, mHeight); - mpRenderbuffer->Bind(); - glFramebufferRenderbuffer( - GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mpRenderbuffer->BufferID() - ); - mpTexture = new CTexture(mWidth, mHeight); - mpTexture->Bind(0); - glFramebufferTexture2D( - GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mpTexture->TextureID(), 0 - ); - - mStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); - - if (mStatus != GL_FRAMEBUFFER_COMPLETE) - Log::Error("Framebuffer not complete"); - + mpRenderbuffer->SetMultisamplingEnabled(mEnableMultisampling); + mpTexture->SetMultisamplingEnabled(mEnableMultisampling); + InitBuffers(); mInitialized = true; } } -void CFramebuffer::Bind() +void CFramebuffer::Bind(GLenum Target /*= GL_FRAMEBUFFER*/) { if (!mInitialized) Init(); - glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer); + glBindFramebuffer(Target, mFramebuffer); } void CFramebuffer::Resize(u32 Width, u32 Height) @@ -81,30 +71,51 @@ void CFramebuffer::Resize(u32 Width, u32 Height) { mpRenderbuffer->Resize(Width, Height); mpTexture->Resize(Width, Height); - - glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer); - mpRenderbuffer->Bind(); - glFramebufferRenderbuffer( - GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mpRenderbuffer->BufferID() - ); - - mpTexture->Bind(0); - glFramebufferTexture2D( - GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mpTexture->TextureID(), 0 - ); + InitBuffers(); } } } -CTexture* CFramebuffer::Texture() +void CFramebuffer::SetMultisamplingEnabled(bool Enable) { - return mpTexture; + if (mEnableMultisampling != Enable) + { + mEnableMultisampling = Enable; + + if (mInitialized) + { + mpRenderbuffer->SetMultisamplingEnabled(Enable); + mpTexture->SetMultisamplingEnabled(Enable); + InitBuffers(); + } + } +} + +// ************ PROTECTED ************ +void CFramebuffer::InitBuffers() +{ + glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer); + + mpRenderbuffer->Bind(); + glFramebufferRenderbuffer( + GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mpRenderbuffer->BufferID() + ); + + mpTexture->Bind(0); + glFramebufferTexture2D( + GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, (mEnableMultisampling ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D), mpTexture->TextureID(), 0 + ); + + mStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); + + if (mStatus != GL_FRAMEBUFFER_COMPLETE) + Log::Error("Framebuffer not complete; error " + TString::HexString((u32) mStatus, 0)); } // ************ STATIC ************ -void CFramebuffer::BindDefaultFramebuffer() +void CFramebuffer::BindDefaultFramebuffer(GLenum Target /*= GL_FRAMEBUFFER*/) { - glBindFramebuffer(GL_FRAMEBUFFER, smDefaultFramebuffer); + glBindFramebuffer(Target, smDefaultFramebuffer); } GLint CFramebuffer::smDefaultFramebuffer; diff --git a/src/Core/OpenGL/CFramebuffer.h b/src/Core/OpenGL/CFramebuffer.h index 640ab71d..bb2c2b04 100644 --- a/src/Core/OpenGL/CFramebuffer.h +++ b/src/Core/OpenGL/CFramebuffer.h @@ -11,6 +11,7 @@ class CFramebuffer CRenderbuffer *mpRenderbuffer; CTexture *mpTexture; u32 mWidth, mHeight; + bool mEnableMultisampling; bool mInitialized; GLenum mStatus; @@ -22,11 +23,18 @@ public: CFramebuffer(u32 Width, u32 Height); ~CFramebuffer(); void Init(); - void Bind(); + void Bind(GLenum Target = GL_FRAMEBUFFER); void Resize(u32 Width, u32 Height); - CTexture* Texture(); - static void BindDefaultFramebuffer(); + void SetMultisamplingEnabled(bool Enable); + // Accessors + inline CTexture* Texture() const { return mpTexture; } + + // Static + static void BindDefaultFramebuffer(GLenum Target = GL_FRAMEBUFFER); + +protected: + void InitBuffers(); }; #endif // CFRAMEBUFFER_H diff --git a/src/Core/OpenGL/CRenderbuffer.h b/src/Core/OpenGL/CRenderbuffer.h index a1e62837..9175af60 100644 --- a/src/Core/OpenGL/CRenderbuffer.h +++ b/src/Core/OpenGL/CRenderbuffer.h @@ -8,20 +8,23 @@ class CRenderbuffer { GLuint mRenderbuffer; u32 mWidth, mHeight; + bool mEnableMultisampling; bool mInitialized; public: CRenderbuffer::CRenderbuffer() - : mInitialized(false) - , mWidth(0) + : mWidth(0) , mHeight(0) + , mEnableMultisampling(false) + , mInitialized(false) { } CRenderbuffer::CRenderbuffer(u32 Width, u32 Height) - : mInitialized(false) - , mWidth(Width) + : mWidth(Width) , mHeight(Height) + , mEnableMultisampling(false) + , mInitialized(false) { } @@ -33,10 +36,9 @@ public: void CRenderbuffer::Init() { - glGenRenderbuffers(1, &mRenderbuffer); - glBindRenderbuffer(GL_RENDERBUFFER, mRenderbuffer); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, mWidth, mHeight); mInitialized = true; + glGenRenderbuffers(1, &mRenderbuffer); + InitStorage(); } inline void CRenderbuffer::Resize(u32 Width, u32 Height) @@ -45,10 +47,7 @@ public: mHeight = Height; if (mInitialized) - { - Bind(); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, mWidth, mHeight); - } + InitStorage(); } inline void CRenderbuffer::Bind() @@ -66,6 +65,26 @@ public: { return mRenderbuffer; } + + inline void SetMultisamplingEnabled(bool Enable) + { + if (mEnableMultisampling != Enable) + { + mEnableMultisampling = Enable; + InitStorage(); + } + } + +private: + void InitStorage() + { + Bind(); + + if (mEnableMultisampling) + glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH_COMPONENT24, mWidth, mHeight); + else + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, mWidth, mHeight); + } }; #endif // CRENDERBUFFER_H diff --git a/src/Core/Render/CRenderer.cpp b/src/Core/Render/CRenderer.cpp index fba261fc..55943461 100644 --- a/src/Core/Render/CRenderer.cpp +++ b/src/Core/Render/CRenderer.cpp @@ -176,6 +176,11 @@ void CRenderer::RenderBloom() CGraphics::SetIdentityMVP(); CGraphics::UpdateMVPBlock(); + mPostProcessFramebuffer.Resize(mViewportWidth, mViewportHeight); + mSceneFramebuffer.Bind(GL_READ_FRAMEBUFFER); + mPostProcessFramebuffer.Bind(GL_DRAW_FRAMEBUFFER); + glBlitFramebuffer(0, 0, mViewportWidth, mViewportHeight, 0, 0, mViewportWidth, mViewportHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); + // Pass 1: Alpha-blend the scene texture on a black background mBloomFramebuffers[0].Resize(BloomWidth, BloomHeight); mBloomFramebuffers[0].Bind(); @@ -183,7 +188,7 @@ void CRenderer::RenderBloom() CDrawUtil::UseTextureShader(); glBlendFunc(GL_SRC_ALPHA, GL_ZERO); - mSceneFramebuffer.Texture()->Bind(0); + mPostProcessFramebuffer.Texture()->Bind(0); CDrawUtil::DrawSquare(); // Pass 2: Horizontal blur @@ -226,7 +231,7 @@ void CRenderer::RenderBloom() } // Render result onto main scene framebuffer - mSceneFramebuffer.Bind(); + mPostProcessFramebuffer.Bind(); glViewport(0, 0, mViewportWidth, mViewportHeight); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); @@ -247,6 +252,11 @@ void CRenderer::RenderBloom() CDrawUtil::DrawSquare(); } + // Copy framebuffer back into the scene framebuffer for more rendering + mPostProcessFramebuffer.Bind(GL_READ_FRAMEBUFFER); + mSceneFramebuffer.Bind(GL_DRAW_FRAMEBUFFER); + glBlitFramebuffer(0, 0, mViewportWidth, mViewportHeight, 0, 0, mViewportWidth, mViewportHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); + // Clean up glEnable(GL_DEPTH_TEST); } @@ -310,6 +320,7 @@ void CRenderer::BeginFrame() CGraphics::SetActiveContext(mContextIndex); glGetIntegerv(GL_FRAMEBUFFER_BINDING, &mDefaultFramebuffer); + mSceneFramebuffer.SetMultisamplingEnabled(true); mSceneFramebuffer.Resize(mViewportWidth, mViewportHeight); mSceneFramebuffer.Bind(); @@ -320,23 +331,11 @@ void CRenderer::BeginFrame() void CRenderer::EndFrame() { - // Render result to screen - glBindFramebuffer(GL_FRAMEBUFFER, mDefaultFramebuffer); - InitFramebuffer(); + // Copy result to the backbuffer + mSceneFramebuffer.Bind(GL_READ_FRAMEBUFFER); + CFramebuffer::BindDefaultFramebuffer(GL_DRAW_FRAMEBUFFER); glViewport(0, 0, mViewportWidth, mViewportHeight); - - CGraphics::SetIdentityMVP(); - CGraphics::UpdateMVPBlock(); - - glDisable(GL_DEPTH_TEST); - - CDrawUtil::UseTextureShader(); - glBlendFunc(GL_ONE, GL_ZERO); - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - mSceneFramebuffer.Texture()->Bind(0); - CDrawUtil::DrawSquare(); - - glEnable(GL_DEPTH_TEST); + glBlitFramebuffer(0, 0, mViewportWidth, mViewportHeight, 0, 0, mViewportWidth, mViewportHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); gDrawCount = 0; } diff --git a/src/Core/Render/CRenderer.h b/src/Core/Render/CRenderer.h index 28bcac25..869c7993 100644 --- a/src/Core/Render/CRenderer.h +++ b/src/Core/Render/CRenderer.h @@ -40,6 +40,7 @@ private: float mBloomHScale, mBloomVScale; CFramebuffer mSceneFramebuffer; + CFramebuffer mPostProcessFramebuffer; CFramebuffer mBloomFramebuffers[3]; GLint mDefaultFramebuffer; diff --git a/src/Core/Resource/CTexture.cpp b/src/Core/Resource/CTexture.cpp index 14a55c2f..aed27a16 100644 --- a/src/Core/Resource/CTexture.cpp +++ b/src/Core/Resource/CTexture.cpp @@ -8,6 +8,7 @@ CTexture::CTexture(CResourceEntry *pEntry /*= 0*/) , mHeight(0) , mNumMipMaps(0) , mLinearSize(0) + , mEnableMultisampling(false) , mBufferExists(false) , mpImgDataBuffer(nullptr) , mImgDataSize(0) @@ -22,6 +23,7 @@ CTexture::CTexture(u32 Width, u32 Height) , mHeight((u16) Height) , mNumMipMaps(1) , mLinearSize(Width * Height * 4) + , mEnableMultisampling(false) , mBufferExists(false) , mpImgDataBuffer(nullptr) , mImgDataSize(0) @@ -36,8 +38,9 @@ CTexture::~CTexture() bool CTexture::BufferGL() { + GLenum BindTarget = (mEnableMultisampling ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D); glGenTextures(1, &mTextureID); - glBindTexture(GL_TEXTURE_2D, mTextureID); + glBindTexture(BindTarget, mTextureID); GLenum GLFormat, GLType; bool IsCompressed = false; @@ -81,9 +84,14 @@ bool CTexture::BufferGL() GLvoid *pData = (mBufferExists) ? (mpImgDataBuffer + MipOffset) : NULL; if (!IsCompressed) - glTexImage2D(GL_TEXTURE_2D, iMip, GLFormat, MipW, MipH, 0, GLFormat, GLType, pData); + { + if (mEnableMultisampling) + glTexImage2DMultisample(BindTarget, 4, GLFormat, MipW, MipH, true); + else + glTexImage2D(BindTarget, iMip, GLFormat, MipW, MipH, 0, GLFormat, GLType, pData); + } else - glCompressedTexImage2D(GL_TEXTURE_2D, iMip, GLFormat, MipW, MipH, 0, MipSize, pData); + glCompressedTexImage2D(BindTarget, iMip, GLFormat, MipW, MipH, 0, MipSize, pData); MipW /= 2; MipH /= 2; @@ -91,17 +99,17 @@ bool CTexture::BufferGL() MipSize /= 4; } - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mNumMipMaps - 1); + glTexParameteri(BindTarget, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(BindTarget, GL_TEXTURE_MAX_LEVEL, mNumMipMaps - 1); // Linear filtering on mipmaps: - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(BindTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(BindTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // Anisotropic filtering: float MaxAnisotropy; glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &MaxAnisotropy); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, MaxAnisotropy); + glTexParameterf(BindTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, MaxAnisotropy); mGLBufferExists = true; return true; @@ -114,7 +122,8 @@ void CTexture::Bind(u32 GLTextureUnit) if (!mGLBufferExists) BufferGL(); - glBindTexture(GL_TEXTURE_2D, mTextureID); + GLenum BindTarget = (mEnableMultisampling ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D); + glBindTexture(BindTarget, mTextureID); } void CTexture::Resize(u32 Width, u32 Height) @@ -323,13 +332,14 @@ void CTexture::CopyGLBuffer() u32 MipW = mWidth, MipH = mHeight, MipOffset = 0; float BytesPerPixel = FormatBPP(mTexelFormat) / 8.f; - glBindTexture(GL_TEXTURE_2D, mTextureID); + GLenum BindTarget = (mEnableMultisampling ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D); + glBindTexture(BindTarget, mTextureID); for (u32 iMip = 0; iMip < mNumMipMaps; iMip++) { void *pData = mpImgDataBuffer + MipOffset; - glGetTexImage(GL_TEXTURE_2D, iMip, GL_RGBA, GL_UNSIGNED_BYTE, pData); + glGetTexImage(BindTarget, iMip, GL_RGBA, GL_UNSIGNED_BYTE, pData); MipOffset += (u32) (MipW * MipH * BytesPerPixel); MipW /= 2; diff --git a/src/Core/Resource/CTexture.h b/src/Core/Resource/CTexture.h index 4ff1becd..bb1e0887 100644 --- a/src/Core/Resource/CTexture.h +++ b/src/Core/Resource/CTexture.h @@ -21,9 +21,10 @@ class CTexture : public CResource u32 mNumMipMaps; // The number of mipmaps this texture has u32 mLinearSize; // The size of the top level mipmap, in bytes - bool mBufferExists; // Indicates whether image data buffer has valid data - u8 *mpImgDataBuffer; // Pointer to image data buffer - u32 mImgDataSize; // Size of image data buffer + bool mEnableMultisampling; // Whether multisample should be enabled (if this texture is a render target). + bool mBufferExists; // Indicates whether image data buffer has valid data + u8 *mpImgDataBuffer; // Pointer to image data buffer + u32 mImgDataSize; // Size of image data buffer bool mGLBufferExists; // Indicates whether GL buffer has valid data GLuint mTextureID; // ID for texture GL buffer @@ -39,7 +40,7 @@ public: float ReadTexelAlpha(const CVector2f& rkTexCoord); bool WriteDDS(IOutputStream& rOut); - // Getters + // Accessors ETexelFormat TexelFormat() const { return mTexelFormat; } ETexelFormat SourceTexelFormat() const { return mSourceTexelFormat; } u32 Width() const { return (u32) mWidth; } @@ -47,6 +48,14 @@ public: u32 NumMipMaps() const { return mNumMipMaps; } GLuint TextureID() const { return mTextureID; } + inline void SetMultisamplingEnabled(bool Enable) + { + if (mEnableMultisampling != Enable) + DeleteBuffers(); + + mEnableMultisampling = Enable; + } + // Static static u32 FormatBPP(ETexelFormat Format); diff --git a/src/Editor/CBasicViewport.cpp b/src/Editor/CBasicViewport.cpp index 17895319..7359edf8 100644 --- a/src/Editor/CBasicViewport.cpp +++ b/src/Editor/CBasicViewport.cpp @@ -32,12 +32,13 @@ void CBasicViewport::initializeGL() CGraphics::Initialize(); // Setting various GL flags - glEnable(GL_PRIMITIVE_RESTART); - glPrimitiveRestartIndex(0xFFFF); - glDepthFunc(GL_LEQUAL); glEnable(GL_BLEND); glEnable(GL_POLYGON_OFFSET_FILL); + glEnable(GL_MULTISAMPLE); + glEnable(GL_PRIMITIVE_RESTART); + glPrimitiveRestartIndex(0xFFFF); glPolygonOffset(1.f, 5.f); + glDepthFunc(GL_LEQUAL); // Clear cached material CMaterial::KillCachedMaterial();