Skip to content

Commit

Permalink
CMAA2 integration (#655)
Browse files Browse the repository at this point in the history
* initial commit

initial implemetation with following compromises:
-redundant copies, since the algorithm is working with UAV in-place
-edge detection happens in LDR; instead HDR luminance diff could be created during tonemapping

* tonemapping changed to compute when CMAA2 is on

tonemapping changed to compute when CMAA2 is on which allows to save perf by not copying tonemap RT into CMAA2 uav (since CMAA2 has effect only on some pixels, where complex or simple shapes are)

* added HDR luminance edge detection

There's a problem with too dark HDR linear, so that edges are not detected with current threshold values

* code cleaning

* merge with upstream

* Revert "merge with upstream"

This reverts commit 5f977fc.

* revert excess updates

* work on comments in review (except for removing MSAA cases)

* removed msaa cases

* macos build fix

* work on review (except for bidnings, remapping and 16x16 threadgroup)

* threadgroup 16x8, removed remapping

* additional fixes

* additional fixes

-indirect buffer size
-naming
-removed extra output formats

* workingControlBuffer refactored

* removed fxaa

* restore libs

* restore libs 2

* code style

* work on review comments

-removed potential descriptor set data races
-removed CMAA2_DEFERRED_APPLY_THREADGROUP_SWAP define

* renamed Cmaa2Preset -> AaPreset

* code style

* implement apply as draw-indirect

* Delete deferred_color_apply_2x2.comp

* cleanup tonemapping

* fixup

* move pack function to common; some naming stuff

* fix layout transition for swapchain

* add indirect commands structs

* merge  image-processing shaders with settingup indirect arguments for the next one

* fixup

* remove more shader options

* compact ubo bindings

* HDR path

* fixup barriers

* final cleanups

---------

Co-authored-by: Try <try9998@gmail.com>
  • Loading branch information
KirillAlekseeenko and Try authored Aug 8, 2024
1 parent 029bdab commit ff2adde
Show file tree
Hide file tree
Showing 19 changed files with 973 additions and 2,234 deletions.
10 changes: 5 additions & 5 deletions game/commandline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,15 +99,15 @@ CommandLine::CommandLine(int argc, const char** argv) {
if(i<argc)
isRQuery = (std::string_view(argv[i])!="0" && std::string_view(argv[i])!="false");
}
else if(arg=="-fxaa") {
else if(arg=="-aa") {
++i;
if(i < argc) {
if(i<argc) {
try {
fxaaPresetId = uint32_t(std::stoul(std::string(argv[i])));
fxaaPresetId = std::clamp(fxaaPresetId, 0u, uint32_t(FxaaPreset::PRESETS_COUNT)-1u);
aaPresetId = uint32_t(std::stoul(std::string(argv[i])));
aaPresetId = std::clamp(aaPresetId, 0u, uint32_t(AaPreset::PRESETS_COUNT)-1u);
}
catch (const std::exception& e) {
Log::i("failed to read fxaa preset: \"", std::string(argv[i]), "\"");
Log::i("failed to read cmaa2 preset: \"", std::string(argv[i]), "\"");
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions game/commandline.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ class CommandLine {
bool doForceG1() const { return forceG1; }
bool doForceG2() const { return forceG2; }
bool doForceG2NR() const { return forceG2NR; }
uint32_t fxaaPreset() const { return fxaaPresetId; }
std::string_view defaultSave() const { return saveDef; }
bool aaPreset() const { return aaPresetId; }
std::string_view defaultSave() const { return saveDef; }

std::string wrldDef;

Expand Down Expand Up @@ -72,6 +72,6 @@ class CommandLine {
bool forceG1 = false;
bool forceG2 = false;
bool forceG2NR = false;
uint32_t fxaaPresetId = 0;
uint32_t aaPresetId = 0;
};

9 changes: 3 additions & 6 deletions game/game/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -468,12 +468,9 @@ enum class ScriptLang : int32_t {
CZ = 7,
};

enum class FxaaPreset : uint32_t {
enum class AaPreset : uint32_t {
OFF,
CONSOLE,
PC_LOW,
PC_MEDIUM,
PC_HIGH,
PC_EXTREME,
MEDIUM,
ULTRA,
PRESETS_COUNT
};
2 changes: 1 addition & 1 deletion game/gothic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ Gothic::Gothic() {
opts.doBindless = CommandLine::inst().isBindless();
}

opts.fxaaPreset = CommandLine::inst().fxaaPreset();
opts.aaPreset = CommandLine::inst().aaPreset();

wrldDef = CommandLine::inst().wrldDef;

Expand Down
2 changes: 1 addition & 1 deletion game/gothic.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class Gothic final {
bool doMeshShading = false;
bool doBindless = false;

uint32_t fxaaPreset = 0;
uint32_t aaPreset = 0;

bool hideFocus = false;
float cameraFov = 67.5f;
Expand Down
130 changes: 86 additions & 44 deletions game/graphics/renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,16 @@ void Renderer::resetSwapchain() {

sceneLinear = device.attachment(TextureFormat::R11G11B10UF,w,h);

if(settings.fxaaEnabled) {
fxaa.sceneTonemapped = device.attachment(TextureFormat::RGBA8, w, h);
if(settings.aaEnabled) {
cmaa2.workingEdges = device.image2d(TextureFormat::R8, (w + 1) / 2, h);
cmaa2.shapeCandidates = device.ssbo(Tempest::Uninitialized, w * h / 4 * sizeof(uint32_t));
cmaa2.deferredBlendLocationList = device.ssbo(Tempest::Uninitialized, (w * h + 3) / 6 * sizeof(uint32_t));
cmaa2.deferredBlendItemList = device.ssbo(Tempest::Uninitialized, w * h * sizeof(uint32_t));
cmaa2.deferredBlendItemListHeads = device.image2d(TextureFormat::R32U, (w + 1) / 2, (h + 1) / 2);
cmaa2.controlBuffer = device.ssbo(nullptr, 5 * sizeof(uint32_t));
cmaa2.indirectBuffer = device.ssbo(nullptr, sizeof(DispatchIndirectCommand) + sizeof(DrawIndirectCommand));
}

zbuffer = device.zbuffer(zBufferFormat,w,h);
if(w!=swapchain.w() || h!=swapchain.h())
zbufferUi = device.zbuffer(zBufferFormat, swapchain.w(), swapchain.h()); else
Expand Down Expand Up @@ -166,11 +172,17 @@ void Renderer::resetSwapchain() {
ssao.ssaoBlur = device.image2d(ssao.aoFormat, w,h);
ssao.uboBlur = device.descriptors(Shaders::inst().ssaoBlur);

tonemapping.pso = (settings.vidResIndex==0) ? &Shaders::inst().tonemapping : &Shaders::inst().tonemappingUpscale;
tonemapping.uboTone = device.descriptors(*tonemapping.pso);
tonemapping.pso = (settings.vidResIndex==0) ? &Shaders::inst().tonemapping : &Shaders::inst().tonemappingUpscale;
tonemapping.uboTone = device.descriptors(*tonemapping.pso);

cmaa2.detectEdges2x2 = &Shaders::inst().cmaa2EdgeColor2x2Presets[Gothic::options().aaPreset];
cmaa2.detectEdges2x2Ubo = device.descriptors(*cmaa2.detectEdges2x2);

fxaa.pso = &Shaders::inst().fxaaPresets[Gothic::options().fxaaPreset];
fxaa.ubo = device.descriptors(*fxaa.pso);
cmaa2.processCandidates = &Shaders::inst().cmaa2ProcessCandidates;
cmaa2.processCandidatesUbo = device.descriptors(*cmaa2.processCandidates);

cmaa2.defferedColorApply = &Shaders::inst().cmaa2DeferredColorApply2x2;
cmaa2.defferedColorApplyUbo = device.descriptors(*cmaa2.defferedColorApply);

initGiData();
prepareUniforms();
Expand All @@ -187,7 +199,8 @@ void Renderer::initSettings() {

auto prevVidResIndex = settings.vidResIndex;
settings.vidResIndex = Gothic::inst().settingsGetF("INTERNAL","vidResIndex");
settings.fxaaEnabled = (Gothic::options().fxaaPreset > 0) && (settings.vidResIndex==0);
settings.aaEnabled = (Gothic::options().aaPreset>0) && (settings.vidResIndex==0);

if(prevVidResIndex!=settings.vidResIndex) {
resetSwapchain();
}
Expand Down Expand Up @@ -291,10 +304,31 @@ void Renderer::prepareUniforms() {
tonemapping.uboTone.set(1, sceneLinear, smpB);
}

if(settings.fxaaEnabled) {
if(settings.aaEnabled) {
auto smpB = Sampler::bilinear();
smpB.setClamping(ClampMode::ClampToEdge);
fxaa.ubo.set(0, fxaa.sceneTonemapped, smpB);

cmaa2.detectEdges2x2Ubo.set(0, sceneLinear, smpB);
cmaa2.detectEdges2x2Ubo.set(1, cmaa2.workingEdges);
cmaa2.detectEdges2x2Ubo.set(2, cmaa2.shapeCandidates);
cmaa2.detectEdges2x2Ubo.set(5, cmaa2.deferredBlendItemListHeads);
cmaa2.detectEdges2x2Ubo.set(6, cmaa2.controlBuffer);
cmaa2.detectEdges2x2Ubo.set(7, cmaa2.indirectBuffer);

cmaa2.processCandidatesUbo.set(0, sceneLinear, smpB);
cmaa2.processCandidatesUbo.set(1, cmaa2.workingEdges);
cmaa2.processCandidatesUbo.set(2, cmaa2.shapeCandidates);
cmaa2.processCandidatesUbo.set(3, cmaa2.deferredBlendLocationList);
cmaa2.processCandidatesUbo.set(4, cmaa2.deferredBlendItemList);
cmaa2.processCandidatesUbo.set(5, cmaa2.deferredBlendItemListHeads);
cmaa2.processCandidatesUbo.set(6, cmaa2.controlBuffer);
cmaa2.processCandidatesUbo.set(7, cmaa2.indirectBuffer);

cmaa2.defferedColorApplyUbo.set(0, sceneLinear);
cmaa2.defferedColorApplyUbo.set(3, cmaa2.deferredBlendLocationList);
cmaa2.defferedColorApplyUbo.set(4, cmaa2.deferredBlendItemList);
cmaa2.defferedColorApplyUbo.set(5, cmaa2.deferredBlendItemListHeads);
cmaa2.defferedColorApplyUbo.set(6, cmaa2.controlBuffer);
}

shadow.ubo.set(0, wview->sceneGlobals().uboGlobal[SceneGlobals::V_Main]);
Expand Down Expand Up @@ -560,26 +594,18 @@ void Renderer::draw(Tempest::Attachment& result, Encoder<CommandBuffer>& cmd, ui
wview->drawFog(cmd,fId);
}

auto* tonemappingRt = &result;
if(settings.fxaaEnabled) {
assert(!fxaa.sceneTonemapped.isEmpty());
tonemappingRt = &fxaa.sceneTonemapped;
}

cmd.setFramebuffer({{*tonemappingRt, Tempest::Discard, Tempest::Preserve}});
cmd.setDebugMarker("Tonemapping");
drawTonemapping(cmd);

if(settings.fxaaEnabled) {
cmd.setFramebuffer({ {result, Tempest::Discard, Tempest::Preserve} });
cmd.setDebugMarker("Fxaa");
drawFxaa(cmd);
if(settings.aaEnabled) {
cmd.setDebugMarker("CMAA2 & Tonemapping");
drawCMAA2(result, cmd);
} else {
cmd.setDebugMarker("Tonemapping");
drawTonemapping(result, cmd);
}

wview->postFrameupdate();
}

void Renderer::drawTonemapping(Encoder<CommandBuffer>& cmd) {
void Renderer::drawTonemapping(Attachment& result, Encoder<CommandBuffer>& cmd) {
struct Push {
float brightness = 0;
float contrast = 1;
Expand All @@ -596,34 +622,50 @@ void Renderer::drawTonemapping(Encoder<CommandBuffer>& cmd) {
if(mul>0)
p.mul = mul;

cmd.setFramebuffer({ {result, Tempest::Discard, Tempest::Preserve} });
cmd.setUniforms(*tonemapping.pso, tonemapping.uboTone, &p, sizeof(p));
cmd.draw(Resources::fsqVbo());
}

void Renderer::drawFxaa(Encoder<CommandBuffer>& cmd) {
void Renderer::drawCMAA2(Tempest::Attachment& result, Tempest::Encoder<Tempest::CommandBuffer>& cmd) {
const IVec3 inputGroupSize = cmaa2.detectEdges2x2->workGroupSize();
const IVec3 outputGroupSize = inputGroupSize - IVec3(2, 2, 0);
const uint32_t groupCountX = uint32_t((sceneLinear.w() + outputGroupSize.x * 2 - 1) / (outputGroupSize.x * 2));
const uint32_t groupCountY = uint32_t((sceneLinear.h() + outputGroupSize.y * 2 - 1) / (outputGroupSize.y * 2));

cmd.setFramebuffer({});

struct PushConstantsFxaa {
float fxaaInverseSharpnessCoeff;
float fxaaQualitySubpix;
float fxaaQualityEdgeThreshold;
float fxaaQualityEdgeThresholdMin;
float fxaaConsoleEdgeSharpness;
float fxaaConsoleEdgeThreshold;
float fxaaConsoleEdgeThresholdMin;
} pushConstantsFxaa;
// detect edges
cmd.setUniforms(*cmaa2.detectEdges2x2, cmaa2.detectEdges2x2Ubo);
cmd.dispatch(groupCountX, groupCountY, 1);

// process candidates pass
cmd.setUniforms(*cmaa2.processCandidates, cmaa2.processCandidatesUbo);
cmd.dispatchIndirect(cmaa2.indirectBuffer, 0);

// deferred color apply
struct Push {
float brightness = 0;
float contrast = 1;
float gamma = 1.f/2.2f;
float mul = 1;
};

Push p;
p.brightness = (settings.zVidBrightness - 0.5f)*0.1f;
p.contrast = std::max(1.5f - settings.zVidContrast, 0.01f);
p.gamma = p.gamma/std::max(2.0f*settings.zVidGamma, 0.01f);

// for now filled with default values (see Fxaa3_11.h)
pushConstantsFxaa.fxaaInverseSharpnessCoeff = 0.5f;
pushConstantsFxaa.fxaaQualitySubpix = 0.75f;
pushConstantsFxaa.fxaaQualityEdgeThreshold = 0.166f;
pushConstantsFxaa.fxaaQualityEdgeThresholdMin = 0.0833f;
pushConstantsFxaa.fxaaConsoleEdgeSharpness = 8.f;
pushConstantsFxaa.fxaaConsoleEdgeThreshold = 0.125f;
pushConstantsFxaa.fxaaConsoleEdgeThresholdMin = 0.05f;
static float mul = 0.f;
if(mul>0)
p.mul = mul;

cmd.setUniforms(*fxaa.pso, fxaa.ubo, &pushConstantsFxaa, sizeof(pushConstantsFxaa));
cmd.setFramebuffer({{result, Tempest::Discard, Tempest::Preserve}});
cmd.setUniforms(*tonemapping.pso, tonemapping.uboTone, &p, sizeof(p));
cmd.draw(Resources::fsqVbo());

cmd.setUniforms(*cmaa2.defferedColorApply, cmaa2.defferedColorApplyUbo, &p, sizeof(p));
cmd.drawIndirect(cmaa2.indirectBuffer, 3*sizeof(uint32_t));
}

void Renderer::stashSceneAux(Encoder<CommandBuffer>& cmd, uint8_t fId) {
Expand Down
33 changes: 23 additions & 10 deletions game/graphics/renderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ class Renderer final {
void drawSky (Tempest::Encoder<Tempest::CommandBuffer>& cmd, uint8_t fId, WorldView& view);
void drawAmbient (Tempest::Encoder<Tempest::CommandBuffer>& cmd, const WorldView& view);
void draw (Tempest::Attachment& result, Tempest::Encoder<Tempest::CommandBuffer>& cmd, uint8_t fId);
void drawTonemapping (Tempest::Encoder<Tempest::CommandBuffer>& cmd);
void drawFxaa (Tempest::Encoder<Tempest::CommandBuffer>& cmd);
void drawTonemapping (Tempest::Attachment& result, Tempest::Encoder<Tempest::CommandBuffer>& cmd);
void drawCMAA2 (Tempest::Attachment& result, Tempest::Encoder<Tempest::CommandBuffer>& cmd);
void drawReflections (Tempest::Encoder<Tempest::CommandBuffer>& cmd, uint8_t fId);
void drawUnderwater (Tempest::Encoder<Tempest::CommandBuffer>& cmd, uint8_t fId);

Expand All @@ -73,7 +73,7 @@ class Renderer final {
bool zEnvMappingEnabled = false;
bool zCloudShadowScale = false;
bool giEnabled = false;
bool fxaaEnabled = false;
bool aaEnabled = false;

float zVidBrightness = 0.5;
float zVidContrast = 0.5;
Expand Down Expand Up @@ -124,15 +124,28 @@ class Renderer final {
} ssao;

struct Tonemapping {
Tempest::RenderPipeline* pso = nullptr;
Tempest::DescriptorSet uboTone;
Tempest::RenderPipeline* pso = nullptr;
Tempest::DescriptorSet uboTone;
} tonemapping;

struct Fxaa {
Tempest::RenderPipeline* pso = nullptr;
Tempest::DescriptorSet ubo;
Tempest::Attachment sceneTonemapped;
} fxaa;
struct Cmaa2 {
Tempest::ComputePipeline* detectEdges2x2 = nullptr;
Tempest::DescriptorSet detectEdges2x2Ubo;

Tempest::ComputePipeline* processCandidates = nullptr;
Tempest::DescriptorSet processCandidatesUbo;

Tempest::RenderPipeline* defferedColorApply = nullptr;
Tempest::DescriptorSet defferedColorApplyUbo;

Tempest::StorageImage workingEdges;
Tempest::StorageBuffer shapeCandidates;
Tempest::StorageBuffer deferredBlendLocationList;
Tempest::StorageBuffer deferredBlendItemList;
Tempest::StorageImage deferredBlendItemListHeads;
Tempest::StorageBuffer controlBuffer;
Tempest::StorageBuffer indirectBuffer;
} cmaa2;

struct {
Tempest::StorageImage hiZ;
Expand Down
19 changes: 12 additions & 7 deletions game/graphics/shaders.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,13 +128,18 @@ Shaders::Shaders() {
tonemapping = postEffect("tonemapping", "tonemapping", RenderState::ZTestMode::Always);
tonemappingUpscale = postEffect("tonemapping", "tonemapping_up", RenderState::ZTestMode::Always);

const auto fxaaZTestMode = RenderState::ZTestMode::Always;
fxaaPresets[uint32_t(FxaaPreset::OFF)] = Tempest::RenderPipeline();
fxaaPresets[uint32_t(FxaaPreset::CONSOLE)] = postEffect("fxaa", "fxaa_quality_0", fxaaZTestMode);
fxaaPresets[uint32_t(FxaaPreset::PC_LOW)] = postEffect("fxaa", "fxaa_quality_1", fxaaZTestMode);
fxaaPresets[uint32_t(FxaaPreset::PC_MEDIUM)] = postEffect("fxaa", "fxaa_quality_2", fxaaZTestMode);
fxaaPresets[uint32_t(FxaaPreset::PC_HIGH)] = postEffect("fxaa", "fxaa_quality_3", fxaaZTestMode);
fxaaPresets[uint32_t(FxaaPreset::PC_EXTREME)] = postEffect("fxaa", "fxaa_quality_4", fxaaZTestMode);
cmaa2EdgeColor2x2Presets[uint32_t(AaPreset::OFF)] = Tempest::ComputePipeline();
cmaa2EdgeColor2x2Presets[uint32_t(AaPreset::MEDIUM)] = computeShader("cmaa2_edges_color2x2_quality_0.comp.sprv");
cmaa2EdgeColor2x2Presets[uint32_t(AaPreset::ULTRA)] = computeShader("cmaa2_edges_color2x2_quality_1.comp.sprv");

cmaa2ProcessCandidates = computeShader("cmaa2_process_candidates.comp.sprv");
{
auto sh = GothicShader::get("cmaa2_deferred_color_apply_2x2.vert.sprv");
auto vs = device.shader(sh.data,sh.len);
sh = GothicShader::get("cmaa2_deferred_color_apply_2x2.frag.sprv");
auto fs = device.shader(sh.data,sh.len);
cmaa2DeferredColorApply2x2 = device.pipeline(Tempest::Points,RenderState(),vs,fs);
}

hiZPot = computeShader("hiz_pot.comp.sprv");
hiZMip = computeShader("hiz_mip.comp.sprv");
Expand Down
4 changes: 3 additions & 1 deletion game/graphics/shaders.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ class Shaders {
Tempest::RenderPipeline tonemapping, tonemappingUpscale;

// AA
Tempest::RenderPipeline fxaaPresets[uint32_t(FxaaPreset::PRESETS_COUNT)];
Tempest::ComputePipeline cmaa2EdgeColor2x2Presets[uint32_t(AaPreset::PRESETS_COUNT)];
Tempest::ComputePipeline cmaa2ProcessCandidates;
Tempest::RenderPipeline cmaa2DeferredColorApply2x2;

// HiZ
Tempest::ComputePipeline hiZPot, hiZMip;
Expand Down
12 changes: 6 additions & 6 deletions shader/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -270,12 +270,12 @@ add_shader(probe_lighting.comp lighting/rt/probe_lighting.comp)
add_shader(probe_ambient.vert copy.vert)
add_shader(probe_ambient.frag lighting/rt/probe_ambient.frag)

add_shader(fxaa.vert copy.vert)
add_shader(fxaa_quality_0.frag antialiasing/fxaa.frag -DFXAA_QUALITY_SETTING=0)
add_shader(fxaa_quality_1.frag antialiasing/fxaa.frag -DFXAA_QUALITY_SETTING=1)
add_shader(fxaa_quality_2.frag antialiasing/fxaa.frag -DFXAA_QUALITY_SETTING=2)
add_shader(fxaa_quality_3.frag antialiasing/fxaa.frag -DFXAA_QUALITY_SETTING=3)
add_shader(fxaa_quality_4.frag antialiasing/fxaa.frag -DFXAA_QUALITY_SETTING=4)
add_shader(cmaa2_edges_color2x2_quality_0.comp antialiasing/cmaa2/edge_color2x2.comp -DCMAA2_STATIC_QUALITY_PRESET=0)
add_shader(cmaa2_edges_color2x2_quality_1.comp antialiasing/cmaa2/edge_color2x2.comp -DCMAA2_STATIC_QUALITY_PRESET=1)

add_shader(cmaa2_process_candidates.comp antialiasing/cmaa2/process_candidates.comp)
add_shader(cmaa2_deferred_color_apply_2x2.vert antialiasing/cmaa2/deferred_color_apply_2x2.vert)
add_shader(cmaa2_deferred_color_apply_2x2.frag antialiasing/cmaa2/deferred_color_apply_2x2.frag)

add_custom_command(
OUTPUT ${HEADER} ${CPP}
Expand Down
Loading

0 comments on commit ff2adde

Please sign in to comment.