1
0
forked from 0ad/0ad

Adds MSAA to anti-aliasing techniques.

Tested By: Freagarach, OptimusShepard, Stan
Differential Revision: https://code.wildfiregames.com/D2812
This was SVN commit r24188.
This commit is contained in:
Vladislav Belov 2020-11-15 20:07:48 +00:00
parent 25490bfec3
commit 9937116f2b
5 changed files with 184 additions and 4 deletions

View File

@ -125,7 +125,11 @@
"config": "antialiasing",
"list": [
{ "value": "disabled", "label": "Disabled", "tooltip": "Do not use anti-aliasing." },
{ "value": "fxaa", "label": "FXAA", "tooltip": "Fast, but simple anti-aliasing." }
{ "value": "fxaa", "label": "FXAA", "tooltip": "Fast, but simple anti-aliasing." },
{ "value": "msaa2", "label": "MSAA (x2)", "tooltip": "Slow, but high-quality anti-aliasing, uses 2 samples per pixel. Supported for GL3.3+." },
{ "value": "msaa4", "label": "MSAA (x4)", "tooltip": "Slow, but high-quality anti-aliasing, uses 4 samples per pixel. Supported for GL3.3+." },
{ "value": "msaa8", "label": "MSAA (x8)", "tooltip": "Slow, but high-quality anti-aliasing, uses 8 samples per pixel. Supported for GL3.3+." },
{ "value": "msaa16", "label": "MSAA (x16)", "tooltip": "Slow, but high-quality anti-aliasing, uses 16 samples per pixel. Supported for GL3.3+." }
],
"function": "Renderer_UpdateAntiAliasingTechnique"
},

View File

@ -144,6 +144,11 @@ typedef GLuint GLhandleARB;
#else
// We might not have multisample on macOS.
#ifndef GL_TEXTURE_2D_MULTISAMPLE
#define GL_TEXTURE_2D_MULTISAMPLE 0x9100
#endif
// were these defined as real functions in gl.h already?
// GL_EXT_draw_range_elements / GL1.2:
@ -385,6 +390,9 @@ FUNC2(void, glGetQueryObjectui64v, glGetQueryObjectui64v, "3.3", (GLuint id, GLe
FUNC2(void*, glMapBufferRange, glMapBufferRange, "3.0", (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access))
FUNC2(void, glFlushMappedBufferRange, glFlushMappedBufferRange, "3.0", (GLenum target, GLintptr offset, GLsizeiptr length))
// GL_ARB_texture_multisample / GL3.3:
FUNC2(void, glTexImage2DMultisample, glTexImage2DMultisample, "3.3", (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations))
// GL_GREMEDY_string_marker (from gDEBugger)
FUNC(int, glStringMarkerGREMEDY, (GLsizei len, const GLvoid *string))

View File

@ -32,13 +32,17 @@
#include "ps/World.h"
#include "renderer/Renderer.h"
#include "renderer/RenderingOptions.h"
#include "tools/atlas/GameInterface/GameLoop.h"
#if !CONFIG2_GLES
CPostprocManager::CPostprocManager()
: m_IsInitialized(false), m_PingFbo(0), m_PongFbo(0), m_PostProcEffect(L"default"), m_ColorTex1(0), m_ColorTex2(0),
m_DepthTex(0), m_BloomFbo(0), m_BlurTex2a(0), m_BlurTex2b(0), m_BlurTex4a(0), m_BlurTex4b(0),
m_BlurTex8a(0), m_BlurTex8b(0), m_WhichBuffer(true), m_Sharpness(0.3f)
: m_IsInitialized(false), m_PingFbo(0), m_PongFbo(0), m_PostProcEffect(L"default"),
m_ColorTex1(0), m_ColorTex2(0), m_DepthTex(0), m_BloomFbo(0), m_BlurTex2a(0),
m_BlurTex2b(0), m_BlurTex4a(0), m_BlurTex4b(0), m_BlurTex8a(0), m_BlurTex8b(0),
m_WhichBuffer(true), m_Sharpness(0.3f), m_UsingMultisampleBuffer(false),
m_MultisampleFBO(0), m_MultisampleColorTex(0), m_MultisampleDepthTex(0),
m_MultisampleCount(0)
{
}
@ -76,6 +80,14 @@ void CPostprocManager::Initialize()
if (m_IsInitialized)
return;
GLint maxSamples = 0;
glGetIntegerv(GL_MAX_SAMPLES, &maxSamples);
const GLsizei possibleSampleCounts[] = {2, 4, 8, 16};
std::copy_if(
std::begin(possibleSampleCounts), std::end(possibleSampleCounts),
std::back_inserter(m_AllowedSampleCounts),
[maxSamples](const GLsizei sampleCount) { return sampleCount <= maxSamples; } );
// The screen size starts out correct and then must be updated with Resize()
m_Width = g_Renderer.GetWidth();
m_Height = g_Renderer.GetHeight();
@ -193,6 +205,12 @@ void CPostprocManager::RecreateBuffers()
}
*/
if (m_UsingMultisampleBuffer)
{
DestroyMultisampleBuffer();
CreateMultisampleBuffer();
}
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}
@ -371,6 +389,13 @@ void CPostprocManager::CaptureRenderOutput()
pglDrawBuffers(1, buffers);
m_WhichBuffer = true;
if (m_UsingMultisampleBuffer)
{
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_MultisampleFBO);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
pglDrawBuffers(1, buffers);
}
}
@ -576,13 +601,52 @@ void CPostprocManager::UpdateAntiAliasingTechnique()
m_AAName = newAAName;
m_AATech.reset();
if (m_UsingMultisampleBuffer)
{
m_UsingMultisampleBuffer = false;
DestroyMultisampleBuffer();
}
// We have to hardcode names in the engine, because anti-aliasing
// techinques strongly depend on the graphics pipeline.
// We might use enums in future though.
const CStr msaaPrefix = "msaa";
if (m_AAName == "fxaa")
{
m_AATech = g_Renderer.GetShaderManager().LoadEffect(CStrIntern("fxaa"));
}
else if (m_AAName.size() > msaaPrefix.size() && m_AAName.substr(0, msaaPrefix.size()) == msaaPrefix)
{
#if !CONFIG2_GLES
// We don't want to enable MSAA in Atlas, because it uses wxWidgets and its canvas.
if (g_AtlasGameLoop && g_AtlasGameLoop->running)
return;
const bool is_msaa_supported =
ogl_HaveVersion("3.3") &&
ogl_HaveExtension("GL_ARB_multisample") &&
ogl_HaveExtension("GL_ARB_texture_multisample") &&
!m_AllowedSampleCounts.empty() &&
g_RenderingOptions.GetPreferGLSL();
if (!is_msaa_supported)
{
LOGWARNING("MSAA is unsupported.");
return;
}
std::stringstream ss(m_AAName.substr(msaaPrefix.size()));
ss >> m_MultisampleCount;
if (std::find(std::begin(m_AllowedSampleCounts), std::end(m_AllowedSampleCounts), m_MultisampleCount) ==
std::end(m_AllowedSampleCounts))
{
m_MultisampleCount = 4;
LOGWARNING("Wrong MSAA sample count: %s.", m_AAName.EscapeToPrintableASCII().c_str());
}
m_UsingMultisampleBuffer = true;
CreateMultisampleBuffer();
#else
#warning TODO: implement and test MSAA for GLES
LOGWARNING("MSAA is unsupported.");
#endif
}
}
void CPostprocManager::UpdateSharpeningTechnique()
@ -614,6 +678,77 @@ void CPostprocManager::SetDepthBufferClipPlanes(float nearPlane, float farPlane)
m_FarPlane = farPlane;
}
void CPostprocManager::CreateMultisampleBuffer()
{
glEnable(GL_MULTISAMPLE);
glGenTextures(1, &m_MultisampleColorTex);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_MultisampleColorTex);
pglTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_MultisampleCount, GL_RGBA, m_Width, m_Height, GL_TRUE);
// Allocate the Depth/Stencil texture.
glGenTextures(1, &m_MultisampleDepthTex);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_MultisampleDepthTex);
pglTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, m_MultisampleCount, GL_DEPTH24_STENCIL8_EXT, m_Width, m_Height, GL_TRUE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
ogl_WarnIfError();
// Set up the framebuffers with some initial textures.
pglGenFramebuffersEXT(1, &m_MultisampleFBO);
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_MultisampleFBO);
pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
GL_TEXTURE_2D_MULTISAMPLE, m_MultisampleColorTex, 0);
pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_STENCIL_ATTACHMENT,
GL_TEXTURE_2D_MULTISAMPLE, m_MultisampleDepthTex, 0);
GLenum status = pglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
{
LOGWARNING("Multisample framebuffer object incomplete (A): 0x%04X", status);
m_UsingMultisampleBuffer = false;
DestroyMultisampleBuffer();
}
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
glBindTexture(GL_TEXTURE_2D, 0);
}
void CPostprocManager::DestroyMultisampleBuffer()
{
if (m_UsingMultisampleBuffer)
return;
if (m_MultisampleFBO)
pglDeleteFramebuffersEXT(1, &m_MultisampleFBO);
if (m_MultisampleColorTex)
glDeleteTextures(1, &m_MultisampleColorTex);
if (m_MultisampleDepthTex)
glDeleteTextures(1, &m_MultisampleDepthTex);
glDisable(GL_MULTISAMPLE);
}
bool CPostprocManager::IsMultisampleEnabled() const
{
return m_UsingMultisampleBuffer;
}
void CPostprocManager::ResolveMultisampleFramebuffer()
{
if (!m_UsingMultisampleBuffer)
return;
pglBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_PingFbo);
pglBlitFramebufferEXT(0, 0, m_Width, m_Height, 0, 0, m_Width, m_Height,
GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PingFbo);
}
#else
#warning TODO: implement PostprocManager for GLES
@ -691,4 +826,21 @@ void CPostprocManager::ReleaseRenderOutput()
{
}
void CPostprocManager::CreateMultisampleBuffer()
{
}
void CPostprocManager::DestroyMultisampleBuffer()
{
}
bool CPostprocManager::IsMultisampleEnabled() const
{
return false;
}
void CPostprocManager::ResolveMultisampleFramebuffer()
{
}
#endif

View File

@ -70,7 +70,15 @@ public:
// @note CPostprocManager must be initialized first
void ReleaseRenderOutput();
// Returns true if we render main scene in the MSAA framebuffer.
bool IsMultisampleEnabled() const;
// Resolves the MSAA framebuffer into the regular one.
void ResolveMultisampleFramebuffer();
private:
void CreateMultisampleBuffer();
void DestroyMultisampleBuffer();
// Two framebuffers, that we flip between at each shader pass.
GLuint m_PingFbo, m_PongFbo;
@ -99,6 +107,11 @@ private:
CStr m_AAName;
CShaderTechniquePtr m_AATech;
bool m_UsingMultisampleBuffer;
GLuint m_MultisampleFBO;
GLuint m_MultisampleColorTex, m_MultisampleDepthTex;
GLsizei m_MultisampleCount;
std::vector<GLsizei> m_AllowedSampleCounts;
// The current screen dimensions in pixels.
int m_Width, m_Height;

View File

@ -1387,6 +1387,9 @@ void CRenderer::RenderSubmissions(const CBoundingBoxAligned& waterScissor)
ogl_WarnIfError();
}
if (g_Renderer.GetPostprocManager().IsMultisampleEnabled())
g_Renderer.GetPostprocManager().ResolveMultisampleFramebuffer();
// render debug-related terrain overlays
ITerrainOverlay::RenderOverlaysAfterWater(cullGroup);
ogl_WarnIfError();