raze-gles/source/common/rendering/hwrenderer/postprocessing/hw_postprocess.h

772 lines
19 KiB
C++

#pragma once
#include "hwrenderer/data/shaderuniforms.h"
#include <memory>
#include <map>
struct PostProcessShader;
typedef FRenderStyle PPBlendMode;
typedef IntRect PPViewport;
class PPTexture;
class PPShader;
enum class PPFilterMode { Nearest, Linear };
enum class PPWrapMode { Clamp, Repeat };
enum class PPTextureType { CurrentPipelineTexture, NextPipelineTexture, PPTexture, SceneColor, SceneFog, SceneNormal, SceneDepth, SwapChain, ShadowMap };
class PPTextureInput
{
public:
PPFilterMode Filter = PPFilterMode::Nearest;
PPWrapMode Wrap = PPWrapMode::Clamp;
PPTextureType Type = PPTextureType::CurrentPipelineTexture;
PPTexture *Texture = nullptr;
};
class PPOutput
{
public:
PPTextureType Type = PPTextureType::NextPipelineTexture;
PPTexture *Texture = nullptr;
};
class PPUniforms
{
public:
PPUniforms()
{
}
PPUniforms(const PPUniforms &src)
{
Data = src.Data;
}
~PPUniforms()
{
Clear();
}
PPUniforms &operator=(const PPUniforms &src)
{
Data = src.Data;
return *this;
}
void Clear()
{
Data.Clear();
}
template<typename T>
void Set(const T &v)
{
if (Data.Size() != (int)sizeof(T))
{
Data.Resize(sizeof(T));
memcpy(Data.Data(), &v, Data.Size());
}
}
TArray<uint8_t> Data;
};
class PPRenderState
{
public:
virtual ~PPRenderState() = default;
virtual void PushGroup(const FString &name) = 0;
virtual void PopGroup() = 0;
virtual void Draw() = 0;
void Clear()
{
Shader = nullptr;
Textures = TArray<PPTextureInput>();
Uniforms = PPUniforms();
Viewport = PPViewport();
BlendMode = PPBlendMode();
Output = PPOutput();
ShadowMapBuffers = false;
}
void SetInputTexture(int index, PPTexture *texture, PPFilterMode filter = PPFilterMode::Nearest, PPWrapMode wrap = PPWrapMode::Clamp)
{
if ((int)Textures.Size() < index + 1)
Textures.Resize(index + 1);
auto &tex = Textures[index];
tex.Filter = filter;
tex.Wrap = wrap;
tex.Type = PPTextureType::PPTexture;
tex.Texture = texture;
}
void SetInputCurrent(int index, PPFilterMode filter = PPFilterMode::Nearest, PPWrapMode wrap = PPWrapMode::Clamp)
{
SetInputSpecialType(index, PPTextureType::CurrentPipelineTexture, filter, wrap);
}
void SetInputSceneColor(int index, PPFilterMode filter = PPFilterMode::Nearest, PPWrapMode wrap = PPWrapMode::Clamp)
{
SetInputSpecialType(index, PPTextureType::SceneColor, filter, wrap);
}
void SetInputSceneFog(int index, PPFilterMode filter = PPFilterMode::Nearest, PPWrapMode wrap = PPWrapMode::Clamp)
{
SetInputSpecialType(index, PPTextureType::SceneFog, filter, wrap);
}
void SetInputSceneNormal(int index, PPFilterMode filter = PPFilterMode::Nearest, PPWrapMode wrap = PPWrapMode::Clamp)
{
SetInputSpecialType(index, PPTextureType::SceneNormal, filter, wrap);
}
void SetInputSceneDepth(int index, PPFilterMode filter = PPFilterMode::Nearest, PPWrapMode wrap = PPWrapMode::Clamp)
{
SetInputSpecialType(index, PPTextureType::SceneDepth, filter, wrap);
}
void SetInputSpecialType(int index, PPTextureType type, PPFilterMode filter = PPFilterMode::Nearest, PPWrapMode wrap = PPWrapMode::Clamp)
{
if ((int)Textures.Size() < index + 1)
Textures.Resize(index + 1);
auto &tex = Textures[index];
tex.Filter = filter;
tex.Wrap = wrap;
tex.Type = type;
tex.Texture = nullptr;
}
void SetShadowMapBuffers(bool enable)
{
ShadowMapBuffers = enable;
}
void SetOutputTexture(PPTexture *texture)
{
Output.Type = PPTextureType::PPTexture;
Output.Texture = texture;
}
void SetOutputCurrent()
{
Output.Type = PPTextureType::CurrentPipelineTexture;
Output.Texture = nullptr;
}
void SetOutputNext()
{
Output.Type = PPTextureType::NextPipelineTexture;
Output.Texture = nullptr;
}
void SetOutputSceneColor()
{
Output.Type = PPTextureType::SceneColor;
Output.Texture = nullptr;
}
void SetOutputSwapChain()
{
Output.Type = PPTextureType::SwapChain;
Output.Texture = nullptr;
}
void SetOutputShadowMap()
{
Output.Type = PPTextureType::ShadowMap;
Output.Texture = nullptr;
}
void SetNoBlend()
{
BlendMode.BlendOp = STYLEOP_Add;
BlendMode.SrcAlpha = STYLEALPHA_One;
BlendMode.DestAlpha = STYLEALPHA_Zero;
BlendMode.Flags = 0;
}
void SetAdditiveBlend()
{
BlendMode.BlendOp = STYLEOP_Add;
BlendMode.SrcAlpha = STYLEALPHA_One;
BlendMode.DestAlpha = STYLEALPHA_One;
BlendMode.Flags = 0;
}
void SetAlphaBlend()
{
BlendMode.BlendOp = STYLEOP_Add;
BlendMode.SrcAlpha = STYLEALPHA_Src;
BlendMode.DestAlpha = STYLEALPHA_InvSrc;
BlendMode.Flags = 0;
}
PPShader *Shader;
TArray<PPTextureInput> Textures;
PPUniforms Uniforms;
PPViewport Viewport;
PPBlendMode BlendMode;
PPOutput Output;
bool ShadowMapBuffers = false;
};
enum class PixelFormat
{
Rgba8,
Rgba16f,
R32f,
Rg16f,
Rgba16_snorm
};
class PPResource
{
public:
PPResource()
{
Next = First;
First = this;
if (Next) Next->Prev = this;
}
PPResource(const PPResource &)
{
Next = First;
First = this;
if (Next) Next->Prev = this;
}
virtual ~PPResource()
{
if (Next) Next->Prev = Prev;
if (Prev) Prev->Next = Next;
else First = Next;
}
PPResource &operator=(const PPResource &other)
{
return *this;
}
static void ResetAll()
{
for (PPResource *cur = First; cur; cur = cur->Next)
cur->ResetBackend();
}
virtual void ResetBackend() = 0;
private:
static PPResource *First;
PPResource *Prev = nullptr;
PPResource *Next = nullptr;
};
class PPTextureBackend
{
public:
virtual ~PPTextureBackend() = default;
};
class PPTexture : public PPResource
{
public:
PPTexture() = default;
PPTexture(int width, int height, PixelFormat format, std::shared_ptr<void> data = {}) : Width(width), Height(height), Format(format), Data(data) { }
void ResetBackend() override { Backend.reset(); }
int Width;
int Height;
PixelFormat Format;
std::shared_ptr<void> Data;
std::unique_ptr<PPTextureBackend> Backend;
};
class PPShaderBackend
{
public:
virtual ~PPShaderBackend() = default;
};
class PPShader : public PPResource
{
public:
PPShader() = default;
PPShader(const FString &fragment, const FString &defines, const std::vector<UniformFieldDesc> &uniforms, int version = 330) : FragmentShader(fragment), Defines(defines), Uniforms(uniforms), Version(version) { }
void ResetBackend() override { Backend.reset(); }
FString VertexShader = "engine/shaders/pp/screenquad.vp";
FString FragmentShader;
FString Defines;
std::vector<UniformFieldDesc> Uniforms;
int Version = 330;
std::unique_ptr<PPShaderBackend> Backend;
};
/////////////////////////////////////////////////////////////////////////////
struct ExtractUniforms
{
FVector2 Scale;
FVector2 Offset;
static std::vector<UniformFieldDesc> Desc()
{
return
{
{ "Scale", UniformType::Vec2, offsetof(ExtractUniforms, Scale) },
{ "Offset", UniformType::Vec2, offsetof(ExtractUniforms, Offset) }
};
}
};
struct BlurUniforms
{
float SampleWeights[8];
static std::vector<UniformFieldDesc> Desc()
{
return
{
{ "SampleWeights0", UniformType::Float, offsetof(BlurUniforms, SampleWeights[0]) },
{ "SampleWeights1", UniformType::Float, offsetof(BlurUniforms, SampleWeights[1]) },
{ "SampleWeights2", UniformType::Float, offsetof(BlurUniforms, SampleWeights[2]) },
{ "SampleWeights3", UniformType::Float, offsetof(BlurUniforms, SampleWeights[3]) },
{ "SampleWeights4", UniformType::Float, offsetof(BlurUniforms, SampleWeights[4]) },
{ "SampleWeights5", UniformType::Float, offsetof(BlurUniforms, SampleWeights[5]) },
{ "SampleWeights6", UniformType::Float, offsetof(BlurUniforms, SampleWeights[6]) },
{ "SampleWeights7", UniformType::Float, offsetof(BlurUniforms, SampleWeights[7]) },
};
}
};
enum { NumBloomLevels = 4 };
class PPBlurLevel
{
public:
PPViewport Viewport;
PPTexture VTexture;
PPTexture HTexture;
};
class PPBloom
{
public:
void RenderBloom(PPRenderState *renderstate, int sceneWidth, int sceneHeight, int fixedcm);
void RenderBlur(PPRenderState *renderstate, int sceneWidth, int sceneHeight, float gameinfobluramount);
private:
void BlurStep(PPRenderState *renderstate, const BlurUniforms &blurUniforms, PPTexture &input, PPTexture &output, PPViewport viewport, bool vertical);
void UpdateTextures(int width, int height);
static float ComputeBlurGaussian(float n, float theta);
static void ComputeBlurSamples(int sampleCount, float blurAmount, float *sampleWeights);
PPBlurLevel levels[NumBloomLevels];
int lastWidth = 0;
int lastHeight = 0;
PPShader BloomCombine = { "engine/shaders/pp/bloomcombine.fp", "", {} };
PPShader BloomExtract = { "engine/shaders/pp/bloomextract.fp", "", ExtractUniforms::Desc() };
PPShader BlurVertical = { "engine/shaders/pp/blur.fp", "#define BLUR_VERTICAL\n", BlurUniforms::Desc() };
PPShader BlurHorizontal = { "engine/shaders/pp/blur.fp", "#define BLUR_HORIZONTAL\n", BlurUniforms::Desc() };
};
/////////////////////////////////////////////////////////////////////////////
struct LensUniforms
{
float AspectRatio;
float Scale;
float Padding0, Padding1;
FVector4 LensDistortionCoefficient;
FVector4 CubicDistortionValue;
static std::vector<UniformFieldDesc> Desc()
{
return
{
{ "Aspect", UniformType::Float, offsetof(LensUniforms, AspectRatio) },
{ "Scale", UniformType::Float, offsetof(LensUniforms, Scale) },
{ "Padding0", UniformType::Float, offsetof(LensUniforms, Padding0) },
{ "Padding1", UniformType::Float, offsetof(LensUniforms, Padding1) },
{ "k", UniformType::Vec4, offsetof(LensUniforms, LensDistortionCoefficient) },
{ "kcube", UniformType::Vec4, offsetof(LensUniforms, CubicDistortionValue) }
};
}
};
class PPLensDistort
{
public:
void Render(PPRenderState *renderstate);
private:
PPShader Lens = { "engine/shaders/pp/lensdistortion.fp", "", LensUniforms::Desc() };
};
/////////////////////////////////////////////////////////////////////////////
struct FXAAUniforms
{
FVector2 ReciprocalResolution;
float Padding0, Padding1;
static std::vector<UniformFieldDesc> Desc()
{
return
{
{ "ReciprocalResolution", UniformType::Vec2, offsetof(FXAAUniforms, ReciprocalResolution) },
{ "Padding0", UniformType::Float, offsetof(FXAAUniforms, Padding0) },
{ "Padding1", UniformType::Float, offsetof(FXAAUniforms, Padding1) }
};
}
};
class PPFXAA
{
public:
void Render(PPRenderState *renderstate);
private:
void CreateShaders();
int GetMaxVersion();
FString GetDefines();
PPShader FXAALuma;
PPShader FXAA;
int LastQuality = -1;
};
/////////////////////////////////////////////////////////////////////////////
struct ExposureExtractUniforms
{
FVector2 Scale;
FVector2 Offset;
static std::vector<UniformFieldDesc> Desc()
{
return
{
{ "Scale", UniformType::Vec2, offsetof(ExposureExtractUniforms, Scale) },
{ "Offset", UniformType::Vec2, offsetof(ExposureExtractUniforms, Offset) }
};
}
};
struct ExposureCombineUniforms
{
float ExposureBase;
float ExposureMin;
float ExposureScale;
float ExposureSpeed;
static std::vector<UniformFieldDesc> Desc()
{
return
{
{ "ExposureBase", UniformType::Float, offsetof(ExposureCombineUniforms, ExposureBase) },
{ "ExposureMin", UniformType::Float, offsetof(ExposureCombineUniforms, ExposureMin) },
{ "ExposureScale", UniformType::Float, offsetof(ExposureCombineUniforms, ExposureScale) },
{ "ExposureSpeed", UniformType::Float, offsetof(ExposureCombineUniforms, ExposureSpeed) }
};
}
};
class PPExposureLevel
{
public:
PPViewport Viewport;
PPTexture Texture;
};
class PPCameraExposure
{
public:
void Render(PPRenderState *renderstate, int sceneWidth, int sceneHeight);
PPTexture CameraTexture = { 1, 1, PixelFormat::R32f };
private:
void UpdateTextures(int width, int height);
std::vector<PPExposureLevel> ExposureLevels;
bool FirstExposureFrame = true;
PPShader ExposureExtract = { "engine/shaders/pp/exposureextract.fp", "", ExposureExtractUniforms::Desc() };
PPShader ExposureAverage = { "engine/shaders/pp/exposureaverage.fp", "", {}, 400 };
PPShader ExposureCombine = { "engine/shaders/pp/exposurecombine.fp", "", ExposureCombineUniforms::Desc() };
};
/////////////////////////////////////////////////////////////////////////////
struct ColormapUniforms
{
FVector4 MapStart;
FVector4 MapRange;
static std::vector<UniformFieldDesc> Desc()
{
return
{
{ "uFixedColormapStart", UniformType::Vec4, offsetof(ColormapUniforms, MapStart) },
{ "uFixedColormapRange", UniformType::Vec4, offsetof(ColormapUniforms, MapRange) },
};
}
};
/////////////////////////////////////////////////////////////////////////////
class PPTonemap
{
public:
void Render(PPRenderState *renderstate);
void ClearTonemapPalette() { PaletteTexture = {}; }
private:
void UpdateTextures();
PPTexture PaletteTexture;
PPShader LinearShader = { "engine/shaders/pp/tonemap.fp", "#define LINEAR\n", {} };
PPShader ReinhardShader = { "engine/shaders/pp/tonemap.fp", "#define REINHARD\n", {} };
PPShader HejlDawsonShader = { "engine/shaders/pp/tonemap.fp", "#define HEJLDAWSON\n", {} };
PPShader Uncharted2Shader = { "engine/shaders/pp/tonemap.fp", "#define UNCHARTED2\n", {} };
PPShader PaletteShader = { "engine/shaders/pp/tonemap.fp", "#define PALETTE\n", {} };
enum TonemapMode
{
None,
Uncharted2,
HejlDawson,
Reinhard,
Linear,
Palette,
NumTonemapModes
};
};
/////////////////////////////////////////////////////////////////////////////
struct LinearDepthUniforms
{
int SampleIndex;
float LinearizeDepthA;
float LinearizeDepthB;
float InverseDepthRangeA;
float InverseDepthRangeB;
float Padding0, Padding1, Padding2;
FVector2 Scale;
FVector2 Offset;
static std::vector<UniformFieldDesc> Desc()
{
return
{
{ "SampleIndex", UniformType::Int, offsetof(LinearDepthUniforms, SampleIndex) },
{ "LinearizeDepthA", UniformType::Float, offsetof(LinearDepthUniforms, LinearizeDepthA) },
{ "LinearizeDepthB", UniformType::Float, offsetof(LinearDepthUniforms, LinearizeDepthB) },
{ "InverseDepthRangeA", UniformType::Float, offsetof(LinearDepthUniforms, InverseDepthRangeA) },
{ "InverseDepthRangeB", UniformType::Float, offsetof(LinearDepthUniforms, InverseDepthRangeB) },
{ "Padding0", UniformType::Float, offsetof(LinearDepthUniforms, Padding0) },
{ "Padding1", UniformType::Float, offsetof(LinearDepthUniforms, Padding1) },
{ "Padding2", UniformType::Float, offsetof(LinearDepthUniforms, Padding2) },
{ "Scale", UniformType::Vec2, offsetof(LinearDepthUniforms, Scale) },
{ "Offset", UniformType::Vec2, offsetof(LinearDepthUniforms, Offset) }
};
}
};
struct SSAOUniforms
{
FVector2 UVToViewA;
FVector2 UVToViewB;
FVector2 InvFullResolution;
float NDotVBias;
float NegInvR2;
float RadiusToScreen;
float AOMultiplier;
float AOStrength;
int SampleIndex;
float Padding0, Padding1;
FVector2 Scale;
FVector2 Offset;
static std::vector<UniformFieldDesc> Desc()
{
return
{
{ "UVToViewA", UniformType::Vec2, offsetof(SSAOUniforms, UVToViewA) },
{ "UVToViewB", UniformType::Vec2, offsetof(SSAOUniforms, UVToViewB) },
{ "InvFullResolution", UniformType::Vec2, offsetof(SSAOUniforms, InvFullResolution) },
{ "NDotVBias", UniformType::Float, offsetof(SSAOUniforms, NDotVBias) },
{ "NegInvR2", UniformType::Float, offsetof(SSAOUniforms, NegInvR2) },
{ "RadiusToScreen", UniformType::Float, offsetof(SSAOUniforms, RadiusToScreen) },
{ "AOMultiplier", UniformType::Float, offsetof(SSAOUniforms, AOMultiplier) },
{ "AOStrength", UniformType::Float, offsetof(SSAOUniforms, AOStrength) },
{ "SampleIndex", UniformType::Int, offsetof(SSAOUniforms, SampleIndex) },
{ "Padding0", UniformType::Float, offsetof(SSAOUniforms, Padding0) },
{ "Padding1", UniformType::Float, offsetof(SSAOUniforms, Padding1) },
{ "Scale", UniformType::Vec2, offsetof(SSAOUniforms, Scale) },
{ "Offset", UniformType::Vec2, offsetof(SSAOUniforms, Offset) },
};
}
};
struct DepthBlurUniforms
{
float BlurSharpness;
float PowExponent;
float Padding0, Padding1;
static std::vector<UniformFieldDesc> Desc()
{
return
{
{ "BlurSharpness", UniformType::Float, offsetof(DepthBlurUniforms, BlurSharpness) },
{ "PowExponent", UniformType::Float, offsetof(DepthBlurUniforms, PowExponent) },
{ "Padding0", UniformType::Float, offsetof(DepthBlurUniforms, Padding0) },
{ "Padding1", UniformType::Float, offsetof(DepthBlurUniforms, Padding1) }
};
}
};
struct AmbientCombineUniforms
{
int SampleCount;
int DebugMode, Padding1, Padding2;
FVector2 Scale;
FVector2 Offset;
static std::vector<UniformFieldDesc> Desc()
{
return
{
{ "SampleCount", UniformType::Int, offsetof(AmbientCombineUniforms, SampleCount) },
{ "DebugMode", UniformType::Int, offsetof(AmbientCombineUniforms, DebugMode) },
{ "Padding1", UniformType::Int, offsetof(AmbientCombineUniforms, Padding1) },
{ "Padding2", UniformType::Int, offsetof(AmbientCombineUniforms, Padding2) },
{ "Scale", UniformType::Vec2, offsetof(AmbientCombineUniforms, Scale) },
{ "Offset", UniformType::Vec2, offsetof(AmbientCombineUniforms, Offset) }
};
}
};
class PPAmbientOcclusion
{
public:
PPAmbientOcclusion();
void Render(PPRenderState *renderstate, float m5, int sceneWidth, int sceneHeight);
private:
void CreateShaders();
void UpdateTextures(int width, int height);
enum Quality
{
Off,
LowQuality,
MediumQuality,
HighQuality,
NumQualityModes
};
int AmbientWidth = 0;
int AmbientHeight = 0;
int LastQuality = -1;
int LastWidth = 0;
int LastHeight = 0;
PPShader LinearDepth;
PPShader LinearDepthMS;
PPShader AmbientOcclude;
PPShader AmbientOccludeMS;
PPShader BlurVertical;
PPShader BlurHorizontal;
PPShader Combine;
PPShader CombineMS;
PPTexture LinearDepthTexture;
PPTexture Ambient0;
PPTexture Ambient1;
enum { NumAmbientRandomTextures = 3 };
PPTexture AmbientRandomTexture[NumAmbientRandomTextures];
};
struct PresentUniforms
{
float InvGamma;
float Contrast;
float Brightness;
float Saturation;
int GrayFormula;
int WindowPositionParity; // top-of-window might not be top-of-screen
FVector2 Scale;
FVector2 Offset;
float ColorScale;
int HdrMode;
static std::vector<UniformFieldDesc> Desc()
{
return
{
{ "InvGamma", UniformType::Float, offsetof(PresentUniforms, InvGamma) },
{ "Contrast", UniformType::Float, offsetof(PresentUniforms, Contrast) },
{ "Brightness", UniformType::Float, offsetof(PresentUniforms, Brightness) },
{ "Saturation", UniformType::Float, offsetof(PresentUniforms, Saturation) },
{ "GrayFormula", UniformType::Int, offsetof(PresentUniforms, GrayFormula) },
{ "WindowPositionParity", UniformType::Int, offsetof(PresentUniforms, WindowPositionParity) },
{ "UVScale", UniformType::Vec2, offsetof(PresentUniforms, Scale) },
{ "UVOffset", UniformType::Vec2, offsetof(PresentUniforms, Offset) },
{ "ColorScale", UniformType::Float, offsetof(PresentUniforms, ColorScale) },
{ "HdrMode", UniformType::Int, offsetof(PresentUniforms, HdrMode) }
};
}
};
class PPPresent
{
public:
PPPresent();
PPTexture Dither;
PPShader Present = { "engine/shaders/pp/present.fp", "", PresentUniforms::Desc() };
PPShader Checker3D = { "engine/shaders/pp/present_checker3d.fp", "", PresentUniforms::Desc() };
PPShader Column3D = { "engine/shaders/pp/present_column3d.fp", "", PresentUniforms::Desc() };
PPShader Row3D = { "engine/shaders/pp/present_row3d.fp", "", PresentUniforms::Desc() };
};
/////////////////////////////////////////////////////////////////////////////
class Postprocess
{
public:
PPBloom bloom;
PPLensDistort lens;
PPFXAA fxaa;
PPCameraExposure exposure;
PPTonemap tonemap;
PPAmbientOcclusion ssao;
PPPresent present;
void Pass1(PPRenderState *state, int fixedcm, int sceneWidth, int sceneHeight);
void Pass2(PPRenderState* state, int fixedcm, int sceneWidth, int sceneHeight);
};
extern Postprocess hw_postprocess;