From d7a316c4265c7d8de4ee215a22ac332493ba072f Mon Sep 17 00:00:00 2001 From: Lywx Date: Sun, 15 Sep 2024 06:08:27 -0600 Subject: [PATCH] Added srgb support (#671) * Added srgb support * Fixed tidy * Moved srgb conversion to the hlsl shader --- src/graphic/Fast3D/Fast3dWindow.cpp | 4 ++++ src/graphic/Fast3D/Fast3dWindow.h | 1 + src/graphic/Fast3D/gfx_direct3d11.cpp | 10 +++++++-- src/graphic/Fast3D/gfx_direct3d12.cpp | 2 +- src/graphic/Fast3D/gfx_direct3d_common.cpp | 26 +++++++++++++++++++--- src/graphic/Fast3D/gfx_direct3d_common.h | 2 +- src/graphic/Fast3D/gfx_metal.cpp | 13 ++++++++--- src/graphic/Fast3D/gfx_opengl.cpp | 25 ++++++++++++++++++++- src/graphic/Fast3D/gfx_rendering_api.h | 1 + 9 files changed, 73 insertions(+), 11 deletions(-) diff --git a/src/graphic/Fast3D/Fast3dWindow.cpp b/src/graphic/Fast3D/Fast3dWindow.cpp index c8073acd3..f915707cf 100644 --- a/src/graphic/Fast3D/Fast3dWindow.cpp +++ b/src/graphic/Fast3D/Fast3dWindow.cpp @@ -134,6 +134,10 @@ void Fast3dWindow::SetTextureFilter(FilteringMode filteringMode) { gfx_get_current_rendering_api()->set_texture_filter(filteringMode); } +void Fast3dWindow::EnableSRGBMode() { + gfx_get_current_rendering_api()->enable_srgb_mode(); +} + void Fast3dWindow::SetRendererUCode(UcodeHandlers ucode) { gfx_set_target_ucode(ucode); } diff --git a/src/graphic/Fast3D/Fast3dWindow.h b/src/graphic/Fast3D/Fast3dWindow.h index 65bba23d0..1f19ac5d0 100644 --- a/src/graphic/Fast3D/Fast3dWindow.h +++ b/src/graphic/Fast3D/Fast3dWindow.h @@ -37,6 +37,7 @@ class Fast3dWindow : public Ship::Window { uint16_t GetPixelDepth(float x, float y); void SetTextureFilter(FilteringMode filteringMode); void SetRendererUCode(UcodeHandlers ucode); + void EnableSRGBMode(); protected: static bool KeyDown(int32_t scancode); diff --git a/src/graphic/Fast3D/gfx_direct3d11.cpp b/src/graphic/Fast3D/gfx_direct3d11.cpp index 1251cd870..bc96472d9 100644 --- a/src/graphic/Fast3D/gfx_direct3d11.cpp +++ b/src/graphic/Fast3D/gfx_direct3d11.cpp @@ -154,6 +154,7 @@ static struct { int8_t last_depth_test = -1; int8_t last_depth_mask = -1; int8_t last_zmode_decal = -1; + bool srgb_mode = false; D3D_PRIMITIVE_TOPOLOGY last_primitive_topology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED; } d3d; @@ -417,7 +418,7 @@ static struct ShaderProgram* gfx_d3d11_create_and_load_new_shader(uint64_t shade size_t len, num_floats; gfx_direct3d_common_build_shader(buf, len, num_floats, cc_features, false, - d3d.current_filter_mode == FILTER_THREE_POINT); + d3d.current_filter_mode == FILTER_THREE_POINT, d3d.srgb_mode); ComPtr vs, ps; ComPtr error_blob; @@ -1228,6 +1229,10 @@ ImTextureID gfx_d3d11_get_texture_by_id(int id) { return d3d.textures[id].resource_view.Get(); } +void gfx_d3d11_enable_srgb_mode(void) { + d3d.srgb_mode = true; +} + struct GfxRenderingAPI gfx_direct3d11_api = { gfx_d3d11_get_name, gfx_d3d11_get_max_texture_size, gfx_d3d11_get_clip_parameters, @@ -1263,6 +1268,7 @@ struct GfxRenderingAPI gfx_direct3d11_api = { gfx_d3d11_get_name, gfx_d3d11_select_texture_fb, gfx_d3d11_delete_texture, gfx_d3d11_set_texture_filter, - gfx_d3d11_get_texture_filter }; + gfx_d3d11_get_texture_filter, + gfx_d3d11_enable_srgb_mode }; #endif diff --git a/src/graphic/Fast3D/gfx_direct3d12.cpp b/src/graphic/Fast3D/gfx_direct3d12.cpp index 27bc69f87..7772ecec3 100644 --- a/src/graphic/Fast3D/gfx_direct3d12.cpp +++ b/src/graphic/Fast3D/gfx_direct3d12.cpp @@ -250,7 +250,7 @@ static struct ShaderProgram* gfx_direct3d12_create_and_load_new_shader(uint32_t char buf[2048]; size_t len, num_floats; - gfx_direct3d_common_build_shader(buf, len, num_floats, cc_features, true, false); + gfx_direct3d_common_build_shader(buf, len, num_floats, cc_features, true, false, false); // fwrite(buf, 1, len, stdout); diff --git a/src/graphic/Fast3D/gfx_direct3d_common.cpp b/src/graphic/Fast3D/gfx_direct3d_common.cpp index e5d8fb16f..8d543aa5d 100644 --- a/src/graphic/Fast3D/gfx_direct3d_common.cpp +++ b/src/graphic/Fast3D/gfx_direct3d_common.cpp @@ -137,7 +137,7 @@ static void append_formula(char* buf, size_t* len, const uint8_t c[2][4], bool d } void gfx_direct3d_common_build_shader(char buf[8192], size_t& len, size_t& num_floats, const CCFeatures& cc_features, - bool include_root_signature, bool three_point_filtering) { + bool include_root_signature, bool three_point_filtering, bool use_srgb) { len = 0; num_floats = 4; @@ -307,6 +307,18 @@ void gfx_direct3d_common_build_shader(char buf[8192], size_t& len, size_t& num_f if (include_root_signature) { append_line(buf, &len, "[RootSignature(RS)]"); } + + if (use_srgb) { + append_line(buf, &len, "float4 fromLinear(float4 linearRGB){"); + append_line(buf, &len, " bool3 cutoff = linearRGB.rgb < float3(0.0031308, 0.0031308, 0.0031308);"); + append_line(buf, &len, + " float3 higher = 1.055 * pow(linearRGB.rgb, float3(1.0 / 2.4, 1.0 / 2.4, 1.0 / 2.4)) - " + "float3(0.055, 0.055, 0.055);"); + append_line(buf, &len, " float3 lower = linearRGB.rgb * float3(12.92, 12.92, 12.92);"); + append_line(buf, &len, " return float4(lerp(higher, lower, cutoff), linearRGB.a);"); + append_line(buf, &len, "}"); + } + append_line(buf, &len, "float4 PSMain(PSInput input, float4 screenSpace : SV_Position) : SV_TARGET {"); // Reference approach to color wrapping as per GLideN64 @@ -473,9 +485,17 @@ void gfx_direct3d_common_build_shader(char buf[8192], size_t& len, size_t& num_f if (cc_features.opt_invisible) { append_line(buf, &len, " texel.a = 0.0;"); } - append_line(buf, &len, " return texel;"); + if (use_srgb) { + append_line(buf, &len, " return fromLinear(texel);"); + } else { + append_line(buf, &len, " return texel;"); + } } else { - append_line(buf, &len, " return float4(texel, 1.0);"); + if (use_srgb) { + append_line(buf, &len, " return fromLinear(float4(texel, 1.0));"); + } else { + append_line(buf, &len, " return float4(texel, 1.0);"); + } } append_line(buf, &len, "}"); } diff --git a/src/graphic/Fast3D/gfx_direct3d_common.h b/src/graphic/Fast3D/gfx_direct3d_common.h index 219efdd0d..aa40d2cfb 100644 --- a/src/graphic/Fast3D/gfx_direct3d_common.h +++ b/src/graphic/Fast3D/gfx_direct3d_common.h @@ -8,7 +8,7 @@ #include "gfx_cc.h" void gfx_direct3d_common_build_shader(char buf[8192], size_t& len, size_t& num_floats, const CCFeatures& cc_features, - bool include_root_signature, bool three_point_filtering); + bool include_root_signature, bool three_point_filtering, bool use_srgb); #endif diff --git a/src/graphic/Fast3D/gfx_metal.cpp b/src/graphic/Fast3D/gfx_metal.cpp index bed5476cc..f052a8f19 100644 --- a/src/graphic/Fast3D/gfx_metal.cpp +++ b/src/graphic/Fast3D/gfx_metal.cpp @@ -163,6 +163,7 @@ static struct { int8_t depth_test; int8_t depth_mask; int8_t zmode_decal; + bool srgb_mode = false; bool non_uniform_threadgroup_supported; } mctx; @@ -369,7 +370,8 @@ static struct ShaderProgram* gfx_metal_create_and_load_new_shader(uint64_t shade pipeline_descriptor->setFragmentFunction(fragmentFunc); pipeline_descriptor->setVertexDescriptor(vertex_descriptor); - pipeline_descriptor->colorAttachments()->object(0)->setPixelFormat(MTL::PixelFormatBGRA8Unorm); + pipeline_descriptor->colorAttachments()->object(0)->setPixelFormat(mctx.srgb_mode ? MTL::PixelFormatBGRA8Unorm_sRGB + : MTL::PixelFormatBGRA8Unorm); pipeline_descriptor->setDepthAttachmentPixelFormat(MTL::PixelFormatDepth32Float); if (cc_features.opt_alpha) { pipeline_descriptor->colorAttachments()->object(0)->setBlendingEnabled(true); @@ -826,7 +828,7 @@ static void gfx_metal_update_framebuffer_parameters(int fb_id, uint32_t width, u tex_descriptor->setHeight(height); tex_descriptor->setSampleCount(1); tex_descriptor->setMipmapLevelCount(1); - tex_descriptor->setPixelFormat(MTL::PixelFormatBGRA8Unorm); + tex_descriptor->setPixelFormat(mctx.srgb_mode ? MTL::PixelFormatBGRA8Unorm_sRGB : MTL::PixelFormatBGRA8Unorm); tex_descriptor->setUsage((render_target ? MTL::TextureUsageRenderTarget : 0) | MTL::TextureUsageShaderRead); if (tex.texture != nullptr) @@ -1225,6 +1227,10 @@ ImTextureID gfx_metal_get_texture_by_id(int fb_id) { return (void*)mctx.textures[fb_id].texture; } +void gfx_metal_enable_srgb_mode(void) { + mctx.srgb_mode = true; +} + struct GfxRenderingAPI gfx_metal_api = { gfx_metal_get_name, gfx_metal_get_max_texture_size, gfx_metal_get_clip_parameters, @@ -1260,5 +1266,6 @@ struct GfxRenderingAPI gfx_metal_api = { gfx_metal_get_name, gfx_metal_select_texture_fb, gfx_metal_delete_texture, gfx_metal_set_texture_filter, - gfx_metal_get_texture_filter }; + gfx_metal_get_texture_filter, + gfx_metal_enable_srgb_mode }; #endif diff --git a/src/graphic/Fast3D/gfx_opengl.cpp b/src/graphic/Fast3D/gfx_opengl.cpp index 028d804a0..f13b37fa8 100644 --- a/src/graphic/Fast3D/gfx_opengl.cpp +++ b/src/graphic/Fast3D/gfx_opengl.cpp @@ -87,6 +87,7 @@ static int8_t current_zmode_decal; static int8_t last_depth_test; static int8_t last_depth_mask; static int8_t last_zmode_decal; +static bool srgb_mode = false; GLint max_msaa_level = 1; GLuint pixel_depth_rb, pixel_depth_fb; @@ -478,6 +479,14 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad append_line(fs_buf, &fs_len, "out vec4 outColor;"); #endif + if (srgb_mode) { + append_line(fs_buf, &fs_len, "vec4 fromLinear(vec4 linearRGB){"); + append_line(fs_buf, &fs_len, " bvec3 cutoff = lessThan(linearRGB.rgb, vec3(0.0031308));"); + append_line(fs_buf, &fs_len, " vec3 higher = vec3(1.055)*pow(linearRGB.rgb, vec3(1.0/2.4)) - vec3(0.055);"); + append_line(fs_buf, &fs_len, " vec3 lower = linearRGB.rgb * vec3(12.92);"); + append_line(fs_buf, &fs_len, "return vec4(mix(higher, lower, cutoff), linearRGB.a);}"); + } + append_line(fs_buf, &fs_len, "void main() {"); // Reference approach to color wrapping as per GLideN64 @@ -620,6 +629,15 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad append_line(fs_buf, &fs_len, "gl_FragColor = vec4(texel, 1.0);"); #endif } + + if (srgb_mode) { +#if defined(__APPLE__) || defined(USE_OPENGLES) + append_line(fs_buf, &fs_len, "outColor = fromLinear(outColor);"); +#else + append_line(fs_buf, &fs_len, "gl_FragColor = fromLinear(gl_FragColor);"); +#endif + } + append_line(fs_buf, &fs_len, "}"); vs_buf[vs_len] = '\0'; @@ -1226,6 +1244,10 @@ FilteringMode gfx_opengl_get_texture_filter(void) { return current_filter_mode; } +void gfx_opengl_enable_srgb_mode(void) { + srgb_mode = true; +} + struct GfxRenderingAPI gfx_opengl_api = { gfx_opengl_get_name, gfx_opengl_get_max_texture_size, gfx_opengl_get_clip_parameters, @@ -1261,6 +1283,7 @@ struct GfxRenderingAPI gfx_opengl_api = { gfx_opengl_get_name, gfx_opengl_select_texture_fb, gfx_opengl_delete_texture, gfx_opengl_set_texture_filter, - gfx_opengl_get_texture_filter }; + gfx_opengl_get_texture_filter, + gfx_opengl_enable_srgb_mode }; #endif diff --git a/src/graphic/Fast3D/gfx_rendering_api.h b/src/graphic/Fast3D/gfx_rendering_api.h index 01959d2f4..ca32e48bc 100644 --- a/src/graphic/Fast3D/gfx_rendering_api.h +++ b/src/graphic/Fast3D/gfx_rendering_api.h @@ -70,6 +70,7 @@ struct GfxRenderingAPI { void (*delete_texture)(uint32_t texID); void (*set_texture_filter)(FilteringMode mode); FilteringMode (*get_texture_filter)(void); + void (*enable_srgb_mode)(void); }; #endif