Gamma by Shader (#7484)

* Replace SDL gamma with a blit shader gamma

* Window_res comment

* Fixes

* Gamma command line flag
This commit is contained in:
BMagnu authored and GitHub committed 2026-07-04 15:28:52 +02:00
1 parent 8b80541046
commit cc63bfa7c1
7 files changed
+58 -112

No files matched your search

@@ -0,0 +1,18 @@
in vec4 fragTexCoord;
out vec4 fragOut0;
uniform sampler2D tex;
layout (std140) uniform genericData {
float gamma;
};
void main()
{
vec4 color = texture(tex, fragTexCoord.xy);
float g = max(gamma, 0.001);
color.rgb = pow(color.rgb, vec3(1.0 / g));
fragOut0 = color;
}
+8 -104
View File
@@ -313,7 +313,7 @@ bool Save_custom_screen_size;
bool Deferred_lighting = false;
bool High_dynamic_range = false;
static ushort* Gr_original_gamma_ramp = nullptr;
static int videodisplay_deserializer(const json_t* value)
{
@@ -755,7 +755,6 @@ void removeVSyncOption()
static std::unique_ptr<graphics::util::UniformBufferManager> UniformBufferManager;
// Forward definitions
static void uniform_buffer_managers_init();
static void uniform_buffer_managers_deinit();
static void uniform_buffer_managers_retire_buffers();
@@ -1305,15 +1304,6 @@ void gr_close()
if(Cmdline_enable_vr)
openxr_close();
if (Gr_original_gamma_ramp != nullptr && os::getSDLMainWindow() != nullptr) {
SDL_SetWindowGammaRamp(os::getSDLMainWindow(), Gr_original_gamma_ramp, (Gr_original_gamma_ramp + 256),
(Gr_original_gamma_ramp + 512));
}
// This is valid even if Gr_original_gamma_ramp is nullptr
vm_free(Gr_original_gamma_ramp);
Gr_original_gamma_ramp = nullptr;
gpu_heap_deinit();
// Cleanup uniform buffer managers
@@ -1870,8 +1860,13 @@ bool gr_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, int d_mode,
// (be that a window, a render overlay from nsight, or an FSO-internal buffer) instead of directly rendering to the OS-provided direct screen backbuffer.
// As the cost of -window_res is one single blit of a fullscreen buffer, it's probably an acceptable compromise to get rid of render artifacts.
// As such, forcibly enable -window_res at the screen resolution here, if we're in fullscreen.
//
// Additionally, SDL3+ doesn't work when reading from the GL_FRONT buffers, so we need our own intermediate buffers.
//
// Furthermore, gamma handling now also requires a blit of the final scene (not just the 3D scene, since it needs to work on menus as well).
//
// As such, window_res is effectively no longer optional, part of the core render path and must always be enabled.
// The only reason it is not yet refactored into an always-on thing is due to issues with FRED integration.
Cmdline_window_res.emplace(static_cast<uint16_t>(width), static_cast<uint16_t>(height));
}
@@ -1984,9 +1979,6 @@ bool gr_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, int d_mode,
gr_light_init();
// Initialize uniform buffer managers
uniform_buffer_managers_init();
gpu_heap_init();
mprintf(("Checking graphics capabilities:\n"));
@@ -2995,7 +2987,7 @@ void gr_print_timestamp(int x, int y, fix timestamp, int resize_mode)
gr_string(x, y, time.c_str(), resize_mode);
}
static void uniform_buffer_managers_init()
void gr_uniform_buffer_managers_init()
{
if (gr_screen.mode == GR_STUB) {
return;
@@ -3197,62 +3189,6 @@ void gr_heap_deallocate(GpuHeap heap_type, size_t data_offset)
gpuHeap->freeGpuData(data_offset);
}
// I feel dirty...
static void make_gamma_ramp(float gamma, ushort* ramp)
{
ushort x, y;
ushort base_ramp[256];
Assert(ramp != nullptr);
// generate the base ramp values first off
// if no gamma set then just do this quickly
if (gamma <= 0.0f) {
memset(ramp, 0, 3 * 256 * sizeof(ushort));
return;
}
// identity gamma, avoid all of the math
else if (gamma == 1.0f || Gr_original_gamma_ramp == nullptr) {
if (Gr_original_gamma_ramp != nullptr) {
memcpy(ramp, Gr_original_gamma_ramp, 3 * 256 * sizeof(ushort));
}
// set identity if no original ramp
else {
for (x = 0; x < 256; x++) {
ramp[x] = (x << 8) | x;
ramp[x + 256] = (x << 8) | x;
ramp[x + 512] = (x << 8) | x;
}
}
return;
}
// for everything else we need to actually figure it up
else {
double g = 1.0 / (double)gamma;
double val;
Assert(Gr_original_gamma_ramp != nullptr);
for (x = 0; x < 256; x++) {
val = (pow(x / 255.0, g) * 65535.0 + 0.5);
CLAMP(val, 0., 65535.);
base_ramp[x] = (ushort)val;
}
for (y = 0; y < 3; y++) {
for (x = 0; x < 256; x++) {
val = (base_ramp[x] * 2) - Gr_original_gamma_ramp[x + y * 256];
CLAMP(val, 0., 65535.);
ramp[x + y * 256] = (ushort)val;
}
}
}
}
void gr_set_gamma(float gamma)
{
if (gr_screen.mode == GR_STUB) {
@@ -3260,38 +3196,6 @@ void gr_set_gamma(float gamma)
}
Gr_gamma = gamma;
// new way - but not while running FRED
if (!Fred_running && !Cmdline_no_set_gamma && os::getSDLMainWindow() != nullptr) {
if (Gr_original_gamma_ramp == nullptr) {
// First time we are here so get the current (original) gamma ramp here so we can reset it later
Gr_original_gamma_ramp = (ushort*)vm_malloc(3 * 256 * sizeof(ushort), memory::quiet_alloc);
if (Gr_original_gamma_ramp == nullptr) {
mprintf((" Unable to allocate memory for gamma ramp! Disabling...\n"));
Cmdline_no_set_gamma = 1;
} else {
SDL_GetWindowGammaRamp(os::getSDLMainWindow(), Gr_original_gamma_ramp, (Gr_original_gamma_ramp + 256),
(Gr_original_gamma_ramp + 512));
}
}
auto gamma_ramp = (ushort*)vm_malloc(3 * 256 * sizeof(ushort), memory::quiet_alloc);
if (gamma_ramp == nullptr) {
Int3();
return;
}
memset(gamma_ramp, 0, 3 * 256 * sizeof(ushort));
// Create the Gamma lookup table
make_gamma_ramp(gamma, gamma_ramp);
SDL_SetWindowGammaRamp(os::getSDLMainWindow(), gamma_ramp, (gamma_ramp + 256), (gamma_ramp + 512));
vm_free(gamma_ramp);
}
}
void gr_get_post_process_effect_names(SCP_vector<SCP_string>& names)
+4
View File
@@ -214,6 +214,8 @@ enum shader_type {
SDR_TYPE_IRRADIANCE_MAP_GEN,
SDR_TYPE_GAMMA_BLIT,
NUM_SHADER_TYPES
};
@@ -1487,6 +1489,8 @@ void gr_get_post_process_effect_names(SCP_vector<SCP_string> &names);
bool gr_is_viewport_window();
void gr_uniform_buffer_managers_init();
// Include this last to make the 2D rendering function available everywhere
#include "graphics/render.h"
+19 -8
View File
@@ -119,15 +119,24 @@ void gr_opengl_flip()
return;
if (Cmdline_window_res) {
GL_state.BindFrameBuffer(0, GL_DRAW_FRAMEBUFFER);
GL_state.BindFrameBuffer(Back_framebuffer, GL_READ_FRAMEBUFFER);
glReadBuffer(GL_COLOR_ATTACHMENT0);
glDrawBuffer(GL_BACK);
glBlitFramebuffer(0, 0, gr_screen.max_w, gr_screen.max_h, 0, 0, Cmdline_window_res->first, Cmdline_window_res->second, GL_COLOR_BUFFER_BIT, GL_LINEAR);
glDrawBuffer(GL_NONE);
GL_state.PopFramebufferState();
glViewport(0, 0, Cmdline_window_res->first, Cmdline_window_res->second);
opengl_shader_set_current(gr_opengl_maybe_create_shader(SDR_TYPE_GAMMA_BLIT, 0));
GL_state.Texture.Enable(0, GL_TEXTURE_2D, Back_texture);
Current_shader->program->Uniforms.setTextureUniform("tex", 0);
GL_state.SetAlphaBlendMode(gr_alpha_blend::ALPHA_BLEND_NONE);
GL_state.SetZbufferType(ZBUFFER_TYPE_NONE);
opengl_set_generic_uniform_data<graphics::generic_data::gamma_blit_data>(
[](graphics::generic_data::gamma_blit_data* data) {
data->gamma = Cmdline_no_set_gamma ? 1.f : Gr_gamma;
});
opengl_draw_full_screen_textured(0.0f, 0.0f, 1.0f, 1.0f);
}
if (Cmdline_gl_finish)
@@ -1485,6 +1494,8 @@ bool gr_opengl_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps)
Gr_current_green = &Gr_green;
Gr_current_alpha = &Gr_alpha;
// Initialize uniform buffer managers
gr_uniform_buffer_managers_init();
gr_setup_frame();
gr_opengl_reset_clip();
+3
View File
@@ -178,6 +178,9 @@ static opengl_shader_type_t GL_shader_types[] = {
{ SDR_TYPE_IRRADIANCE_MAP_GEN, "post-v.sdr", "irrmap-f.sdr", nullptr,
{ opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD }, "Irradiance Map Generation", false },
{ SDR_TYPE_GAMMA_BLIT, "post-v.sdr", "gamma-correct-f.sdr", nullptr,
{ opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD }, "Gamma correct blit", false },
};
// clang-format on
+5
View File
@@ -408,6 +408,11 @@ struct irrmap_data {
int face;
};
struct gamma_blit_data {
float gamma;
float pad[3];
};
} // namespace generic_data
} // namespace graphics
+1
View File
@@ -247,6 +247,7 @@ add_file_folder("Default files\\\\data\\\\effects"
def_files/data/effects/fxaa-v.sdr
def_files/data/effects/fxaapre-f.sdr
def_files/data/effects/gamma.sdr
def_files/data/effects/gamma-correct-f.sdr
def_files/data/effects/irrmap-f.sdr
def_files/data/effects/lighting.sdr
def_files/data/effects/ls-f.sdr