Skip to content

Commit

Permalink
Added --fp16 and --fp32 options to reduce color banding
Browse files Browse the repository at this point in the history
These options will use more GPU memory and incur a performance penalty,
and may not be supported on all hardware.

They create an additional floating point FBO at full screen resolution,
which is then transferred to the default FBO by rendering a full screen quad.
  • Loading branch information
hyperlogic committed May 31, 2024
1 parent 5e9207c commit 22ff617
Show file tree
Hide file tree
Showing 7 changed files with 201 additions and 6 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ find_package(OpenXR CONFIG REQUIRED)
include_directories(src)
add_executable(${PROJECT_NAME}
src/core/debugrenderer.cpp
src/core/framebuffer.cpp
src/core/image.cpp
src/core/inputbuddy.cpp
src/core/log.cpp
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ Options
-d, --debug
enable debug logging

--fp16
Use 16-bit half-precision floating frame buffer, to reduce color banding artifacts

--fp32
Use 32-bit floating point frame buffer, to reduce color banding even more

-h, --help
show help

Expand Down
86 changes: 80 additions & 6 deletions src/app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@
#include <filesystem>
#include <thread>

#include "core/framebuffer.h"
#include "core/log.h"
#include "core/debugrenderer.h"
#include "core/inputbuddy.h"
#include "core/optionparser.h"
#include "core/textrenderer.h"
#include "core/texture.h"
#include "core/util.h"
#include "core/xrbuddy.h"

Expand All @@ -41,7 +43,9 @@ enum optionIndex
OPENXR,
FULLSCREEN,
DEBUG,
HELP
HELP,
FP16,
FP32
};

const option::Descriptor usage[] =
Expand All @@ -51,6 +55,8 @@ const option::Descriptor usage[] =
{ OPENXR, 0, "v", "openxr", option::Arg::None, " -v, --openxr Launch app in vr mode, using openxr runtime." },
{ FULLSCREEN, 0, "f", "fullscren", option::Arg::None, " -f, --fullscreen Launch window in fullscreen." },
{ DEBUG, 0, "d", "debug", option::Arg::None, " -d, --debug Enable verbose debug logging." },
{ FP16, 0, "", "fp16", option::Arg::None, " --fp16 Use 16-bit half-precision floating frame buffer, to reduce color banding artifacts" },
{ FP32, 0, "", "fp32", option::Arg::None, " --fp32 Use 32-bit floating point frame buffer, to reduce color banding even more" },
{ UNKNOWN, 0, "", "", option::Arg::None, "\nExamples:\n splataplut data/test.ply\n splatapult -v data/test.ply" },
{ 0, 0, 0, 0, 0, 0}
};
Expand Down Expand Up @@ -156,7 +162,7 @@ static void Clear(glm::ivec2 windowSize, bool setViewport = true)
}

// Draw a textured quad over the entire screen.
static void RenderDesktop(glm::ivec2 windowSize, std::shared_ptr<Program> desktopProgram, uint32_t colorTexture)
static void RenderDesktop(glm::ivec2 windowSize, std::shared_ptr<Program> desktopProgram, uint32_t colorTexture, bool adjustAspect)
{
int width = windowSize.x;
int height = windowSize.y;
Expand All @@ -178,8 +184,13 @@ static void RenderDesktop(glm::ivec2 windowSize, std::shared_ptr<Program> deskto
glBindTexture(GL_TEXTURE_2D, colorTexture);
desktopProgram->SetUniform("colorTexture", 0);

glm::vec2 xyLowerLeft(0.0f, (height - width) / 2.0f);
glm::vec2 xyUpperRight((float)width, (height + width) / 2.0f);
glm::vec2 xyLowerLeft(0.0f, 0.0f);
glm::vec2 xyUpperRight((float)width, (float)height);
if (adjustAspect)
{
xyLowerLeft = glm::vec2(0.0f, (height - width) / 2.0f);
xyUpperRight = glm::vec2((float)width, (height + width) / 2.0f);
}
glm::vec2 uvLowerLeft(0.0f, 0.0f);
glm::vec2 uvUpperRight(1.0f, 1.0f);

Expand Down Expand Up @@ -305,6 +316,15 @@ App::ParseResult App::ParseArguments(int argc, const char* argv[])
opt.debugLogging = true;
}

if (options[FP32])
{
opt.frameBuffer = Options::FrameBuffer::Float;
}
else if (options[FP16])
{
opt.frameBuffer = Options::FrameBuffer::HalfFloat;
}

bool unknownOptionFound = false;
for (option::Option* opt = options[UNKNOWN]; opt; opt = opt->next())
{
Expand Down Expand Up @@ -533,7 +553,6 @@ bool App::Init()

if (opt.vrMode)
{
// TODO: move this into a DesktopRenderer class
desktopProgram = std::make_shared<Program>();
std::string defines = "#define USE_SUPERSAMPLING\n";
desktopProgram->AddMacro("DEFINES", defines);
Expand Down Expand Up @@ -583,6 +602,16 @@ bool App::Init()
});
}

if (!opt.vrMode && opt.frameBuffer != Options::FrameBuffer::Default)
{
desktopProgram = std::make_shared<Program>();
if (!desktopProgram->LoadVertFrag("shader/desktop_vert.glsl", "shader/desktop_frag.glsl"))
{
Log::E("Error loading desktop shader!\n");
return 1;
}
}

#ifdef USE_SDL
inputBuddy = std::make_shared<InputBuddy>();

Expand Down Expand Up @@ -948,7 +977,7 @@ bool App::Render(float dt, const glm::ivec2& windowSize)
#ifndef __ANDROID__
// render desktop.
Clear(windowSize, true);
RenderDesktop(windowSize, desktopProgram, xrBuddy->GetColorTexture());
RenderDesktop(windowSize, desktopProgram, xrBuddy->GetColorTexture(), true);

if (opt.drawFps)
{
Expand All @@ -961,6 +990,43 @@ bool App::Render(float dt, const glm::ivec2& windowSize)
}
else
{
// lazy init of fbo, fbo is only used for HalfFloat, Float option.
if (opt.frameBuffer != Options::FrameBuffer::Default && fboSize != windowSize)
{
fbo = std::make_shared<FrameBuffer>();

Texture::Params texParams;
texParams.minFilter = FilterType::Nearest;
texParams.magFilter = FilterType::Nearest;
texParams.sWrap = WrapType::ClampToEdge;
texParams.tWrap = WrapType::ClampToEdge;
if (opt.frameBuffer == Options::FrameBuffer::HalfFloat)
{
fboColorTex = std::make_shared<Texture>(windowSize.x, windowSize.y,
GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT,
texParams);
}
else if (opt.frameBuffer == Options::FrameBuffer::Float)
{
fboColorTex = std::make_shared<Texture>(windowSize.x, windowSize.y,
GL_RGBA32F, GL_RGBA, GL_FLOAT,
texParams);
}
else
{
Log::E("BAD opt.frameBuffer type!\n");
}

fbo->AttachColor(fboColorTex);

fboSize = windowSize;
}

if (opt.frameBuffer != Options::FrameBuffer::Default && fbo)
{
fbo->Bind();
}

Clear(windowSize, true);

glm::mat4 cameraMat = flyCam->GetCameraMat();
Expand Down Expand Up @@ -999,6 +1065,14 @@ bool App::Render(float dt, const glm::ivec2& windowSize)
{
textRenderer->Render(cameraMat, projMat, viewport, nearFar);
}

if (opt.frameBuffer != Options::FrameBuffer::Default && fbo)
{
// render fbo colorTexture as a full screen quad to the default fbo
glBindFramebuffer(GL_FRAMEBUFFER, 0);
Clear(windowSize, true);
RenderDesktop(windowSize, desktopProgram, fbo->GetColorTexture()->texture, false);
}
}

debugRenderer->EndFrame();
Expand Down
13 changes: 13 additions & 0 deletions src/app.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class CamerasConfig;
class CameraPathRenderer;
class DebugRenderer;
class FlyCam;
class FrameBuffer;
class GaussianCloud;
class InputBuddy;
class MagicCarpet;
Expand All @@ -24,6 +25,7 @@ class PointRenderer;
class Program;
class SplatRenderer;
class TextRenderer;
struct Texture;
class VrConfig;
class XrBuddy;

Expand Down Expand Up @@ -58,8 +60,15 @@ class App
protected:
struct Options
{
enum class FrameBuffer
{
Default,
HalfFloat,
Float
};
bool vrMode = false;
bool fullscreen = false;
FrameBuffer frameBuffer = FrameBuffer::Default;
bool drawCarpet = false;
bool drawPointCloud = false;
bool drawDebug = true;
Expand Down Expand Up @@ -90,6 +99,10 @@ class App
std::shared_ptr<SplatRenderer> splatRenderer;

std::shared_ptr<Program> desktopProgram;
std::shared_ptr<FrameBuffer> fbo;
glm::ivec2 fboSize = {0, 0};
std::shared_ptr<Texture> fboColorTex;

std::shared_ptr<InputBuddy> inputBuddy;

glm::vec2 virtualLeftStick;
Expand Down
62 changes: 62 additions & 0 deletions src/core/framebuffer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
Copyright (c) 2024 Anthony J. Thibault
This software is licensed under the MIT License. See LICENSE for more details.
*/

#include "framebuffer.h"

#ifdef __ANDROID__
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES3/gl3.h>
#include <GLES3/gl3ext.h>
#else
#include <GL/glew.h>
#define GL_GLEXT_PROTOTYPES 1
#include <SDL2/SDL_opengl.h>
#include <SDL2/SDL_opengl_glext.h>
#endif

#include "texture.h"

FrameBuffer::FrameBuffer()
{
glGenFramebuffers(1, &fbo);
}

FrameBuffer::~FrameBuffer()
{
glDeleteFramebuffers(1, &fbo);
fbo = 0;
}

void FrameBuffer::Bind() const
{
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
}

void FrameBuffer::AttachColor(std::shared_ptr<Texture> colorTex)
{
Bind();
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTex->texture, 0);
colorAttachment = colorTex;
}

void FrameBuffer::AttachDepth(std::shared_ptr<Texture> depthTex)
{
Bind();
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTex->texture, 0);
depthAttachment = depthTex;
}

void FrameBuffer::AttachStencil(std::shared_ptr<Texture> stencilTex)
{
Bind();
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, stencilTex->texture, 0);
stencilAttachment = stencilTex;
}

bool FrameBuffer::IsComplete() const
{
return glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE;
}
33 changes: 33 additions & 0 deletions src/core/framebuffer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
Copyright (c) 2024 Anthony J. Thibault
This software is licensed under the MIT License. See LICENSE for more details.
*/

#pragma once

#include <stdint.h>
#include <memory>

struct Texture;

struct FrameBuffer
{
FrameBuffer();
~FrameBuffer();

void Bind() const;
void AttachColor(std::shared_ptr<Texture> colorTex);
void AttachDepth(std::shared_ptr<Texture> depthTex);
void AttachStencil(std::shared_ptr<Texture> stencilTex);

bool IsComplete() const;

std::shared_ptr<Texture> GetColorTexture() const { return colorAttachment; }
std::shared_ptr<Texture> GetDepthTexture() const { return depthAttachment; }
std::shared_ptr<Texture> GetStencilTexture() const { return stencilAttachment; }

uint32_t fbo;
std::shared_ptr<Texture> colorAttachment;
std::shared_ptr<Texture> depthAttachment;
std::shared_ptr<Texture> stencilAttachment;
};
6 changes: 6 additions & 0 deletions src/sdl_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,12 @@ int main(int argc, char *argv[])
}
ctx.window = SDL_CreateWindow("splatapult", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WIDTH, HEIGHT, windowFlags);

if (!ctx.window)
{
Log::E("Failed to create window: %s\n", SDL_GetError());
return 1;
}

ctx.gl_context = SDL_GL_CreateContext(ctx.window);

SDL_GL_MakeCurrent(ctx.window, ctx.gl_context);
Expand Down

0 comments on commit 22ff617

Please sign in to comment.