1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-09-15 18:57:08 +00:00

Implement support for FSAA in combination with post-processing (#15392)

- Actually it's MSAA I think, or perhaps the terms are equivalent
- I've made it fit into the existing Irrlicht architecture, but that has resulted in code duplication compared to my original "hacky" approach
- OpenGL 3.2+ and OpenGL ES 3.1+ are supported
- EDT_OPENGL3 is not required, EDT_OPENGL works too
- Helpful tutorial: https://learnopengl.com/Advanced-OpenGL/Anti-Aliasing, section "Off-screen MSAA"
- This may be rough around the edges, but in general it works
This commit is contained in:
grorp 2024-11-18 14:06:48 +01:00 committed by GitHub
parent a8ea165042
commit 9b6a399011
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 290 additions and 42 deletions

View file

@ -26,7 +26,7 @@ video::ITexture *TextureBuffer::getTexture(u8 index)
}
void TextureBuffer::setTexture(u8 index, core::dimension2du size, const std::string &name, video::ECOLOR_FORMAT format, bool clear)
void TextureBuffer::setTexture(u8 index, core::dimension2du size, const std::string &name, video::ECOLOR_FORMAT format, bool clear, u8 msaa)
{
assert(index != NO_DEPTH_TEXTURE);
@ -41,9 +41,10 @@ void TextureBuffer::setTexture(u8 index, core::dimension2du size, const std::str
definition.name = name;
definition.format = format;
definition.clear = clear;
definition.msaa = msaa;
}
void TextureBuffer::setTexture(u8 index, v2f scale_factor, const std::string &name, video::ECOLOR_FORMAT format, bool clear)
void TextureBuffer::setTexture(u8 index, v2f scale_factor, const std::string &name, video::ECOLOR_FORMAT format, bool clear, u8 msaa)
{
assert(index != NO_DEPTH_TEXTURE);
@ -58,6 +59,7 @@ void TextureBuffer::setTexture(u8 index, v2f scale_factor, const std::string &na
definition.name = name;
definition.format = format;
definition.clear = clear;
definition.msaa = msaa;
}
void TextureBuffer::reset(PipelineContext &context)
@ -125,13 +127,19 @@ bool TextureBuffer::ensureTexture(video::ITexture **texture, const TextureDefini
if (definition.valid) {
if (definition.clear) {
// We're not able to clear a render target texture
// We're not able to create a normal texture with MSAA
// (could be solved by more refactoring in Irrlicht, but not needed for now)
sanity_check(definition.msaa < 1);
video::IImage *image = m_driver->createImage(definition.format, size);
// Cannot use image->fill because it's not implemented for all formats.
std::memset(image->getData(), 0, image->getDataSizeFromFormat(definition.format, size.Width, size.Height));
*texture = m_driver->addTexture(definition.name.c_str(), image);
image->drop();
}
else {
} else if (definition.msaa > 0) {
*texture = m_driver->addRenderTargetTextureMs(size, definition.msaa, definition.name.c_str(), definition.format);
} else {
*texture = m_driver->addRenderTargetTexture(size, definition.name.c_str(), definition.format);
}
}
@ -189,6 +197,12 @@ void TextureBufferOutput::activate(PipelineContext &context)
RenderTarget::activate(context);
}
video::IRenderTarget *TextureBufferOutput::getIrrRenderTarget(PipelineContext &context)
{
activate(context); // Needed to make sure that render_target is set up.
return render_target;
}
u8 DynamicSource::getTextureCount()
{
assert(isConfigured());

View file

@ -117,7 +117,7 @@ public:
* @param name unique name of the texture
* @param format color format
*/
void setTexture(u8 index, core::dimension2du size, const std::string& name, video::ECOLOR_FORMAT format, bool clear = false);
void setTexture(u8 index, core::dimension2du size, const std::string& name, video::ECOLOR_FORMAT format, bool clear = false, u8 msaa = 0);
/**
* Configure relative-size texture for the specific index
@ -127,7 +127,7 @@ public:
* @param name unique name of the texture
* @param format color format
*/
void setTexture(u8 index, v2f scale_factor, const std::string& name, video::ECOLOR_FORMAT format, bool clear = false);
void setTexture(u8 index, v2f scale_factor, const std::string& name, video::ECOLOR_FORMAT format, bool clear = false, u8 msaa = 0);
virtual u8 getTextureCount() override { return m_textures.size(); }
virtual video::ITexture *getTexture(u8 index) override;
@ -146,6 +146,7 @@ private:
core::dimension2du size;
std::string name;
video::ECOLOR_FORMAT format;
u8 msaa;
};
/**
@ -174,6 +175,9 @@ public:
TextureBufferOutput(TextureBuffer *buffer, const std::vector<u8> &texture_map, u8 depth_stencil);
virtual ~TextureBufferOutput() override;
void activate(PipelineContext &context) override;
video::IRenderTarget *getIrrRenderTarget(PipelineContext &context);
private:
static const u8 NO_DEPTH_TEXTURE = 255;

View file

@ -9,6 +9,7 @@
#include "client/shader.h"
#include "client/tile.h"
#include "settings.h"
#include "mt_opengl.h"
PostProcessingStep::PostProcessingStep(u32 _shader_id, const std::vector<u8> &_texture_map) :
shader_id(_shader_id), texture_map(_texture_map)
@ -102,21 +103,45 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep
static const u8 TEXTURE_EXPOSURE_2 = 4;
static const u8 TEXTURE_FXAA = 5;
static const u8 TEXTURE_VOLUME = 6;
static const u8 TEXTURE_MSAA_COLOR = 7;
static const u8 TEXTURE_MSAA_DEPTH = 8;
static const u8 TEXTURE_SCALE_DOWN = 10;
static const u8 TEXTURE_SCALE_UP = 20;
// Super-sampling is simply rendering into a larger texture.
// Downscaling is done by the final step when rendering to the screen.
const std::string antialiasing = g_settings->get("antialiasing");
const bool enable_bloom = g_settings->getBool("enable_bloom");
const bool enable_volumetric_light = g_settings->getBool("enable_volumetric_lighting") && enable_bloom;
const bool enable_auto_exposure = g_settings->getBool("enable_auto_exposure");
const std::string antialiasing = g_settings->get("antialiasing");
const u16 antialiasing_scale = MYMAX(2, g_settings->getU16("fsaa"));
// This code only deals with MSAA in combination with post-processing. MSAA without
// post-processing works via a flag at OpenGL context creation instead.
// To make MSAA work with post-processing, we need multisample texture support,
// which has higher OpenGL (ES) version requirements.
// Note: This is not about renderbuffer objects, but about textures,
// since that's what we use and what Irrlicht allows us to use.
const bool msaa_available = driver->queryFeature(video::EVDF_TEXTURE_MULTISAMPLE);
const bool enable_msaa = antialiasing == "fsaa" && msaa_available;
if (antialiasing == "fsaa" && !msaa_available)
warningstream << "Ignoring configured FSAA. FSAA is not supported in "
<< "combination with post-processing by the current video driver." << std::endl;
const bool enable_ssaa = antialiasing == "ssaa";
const bool enable_fxaa = antialiasing == "fxaa";
const bool enable_volumetric_light = g_settings->getBool("enable_volumetric_lighting") && enable_bloom;
// Super-sampling is simply rendering into a larger texture.
// Downscaling is done by the final step when rendering to the screen.
if (enable_ssaa) {
u16 ssaa_scale = MYMAX(2, g_settings->getU16("fsaa"));
scale *= ssaa_scale;
scale *= antialiasing_scale;
}
if (enable_msaa) {
buffer->setTexture(TEXTURE_MSAA_COLOR, scale, "3d_render_msaa", color_format, false, antialiasing_scale);
buffer->setTexture(TEXTURE_MSAA_DEPTH, scale, "3d_depthmap_msaa", depth_format, false, antialiasing_scale);
}
buffer->setTexture(TEXTURE_COLOR, scale, "3d_render", color_format);
@ -125,7 +150,14 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep
buffer->setTexture(TEXTURE_DEPTH, scale, "3d_depthmap", depth_format);
// attach buffer to the previous step
previousStep->setRenderTarget(pipeline->createOwned<TextureBufferOutput>(buffer, std::vector<u8> { TEXTURE_COLOR }, TEXTURE_DEPTH));
if (enable_msaa) {
TextureBufferOutput *msaa = pipeline->createOwned<TextureBufferOutput>(buffer, std::vector<u8> { TEXTURE_MSAA_COLOR }, TEXTURE_MSAA_DEPTH);
previousStep->setRenderTarget(msaa);
TextureBufferOutput *normal = pipeline->createOwned<TextureBufferOutput>(buffer, std::vector<u8> { TEXTURE_COLOR }, TEXTURE_DEPTH);
pipeline->addStep<ResolveMSAAStep>(msaa, normal);
} else {
previousStep->setRenderTarget(pipeline->createOwned<TextureBufferOutput>(buffer, std::vector<u8> { TEXTURE_COLOR }, TEXTURE_DEPTH));
}
// shared variables
u32 shader_id;
@ -234,3 +266,9 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep
return effect;
}
void ResolveMSAAStep::run(PipelineContext &context)
{
context.device->getVideoDriver()->blitRenderTarget(msaa_fbo->getIrrRenderTarget(context),
target_fbo->getIrrRenderTarget(context));
}

View file

@ -44,4 +44,18 @@ private:
void configureMaterial();
};
class ResolveMSAAStep : public TrivialRenderStep
{
public:
ResolveMSAAStep(TextureBufferOutput *_msaa_fbo, TextureBufferOutput *_target_fbo) :
msaa_fbo(_msaa_fbo), target_fbo(_target_fbo) {};
void run(PipelineContext &context) override;
private:
TextureBufferOutput *msaa_fbo;
TextureBufferOutput *target_fbo;
};
RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep, v2f scale, Client *client);

View file

@ -179,7 +179,10 @@ RenderingEngine::RenderingEngine(MyEventReceiver *receiver)
// bpp, fsaa, vsync
bool vsync = g_settings->getBool("vsync");
bool enable_fsaa = g_settings->get("antialiasing") == "fsaa";
// Don't enable MSAA in OpenGL context creation if post-processing is enabled,
// the post-processing pipeline handles it.
bool enable_fsaa = g_settings->get("antialiasing") == "fsaa" &&
!g_settings->getBool("enable_post_processing");
u16 fsaa = enable_fsaa ? MYMAX(2, g_settings->getU16("fsaa")) : 0;
// Determine driver