Detailed changes
@@ -696,6 +696,7 @@ features = [
"Win32_Graphics_Dxgi_Common",
"Win32_Graphics_Gdi",
"Win32_Graphics_Imaging",
+ "Win32_Graphics_Hlsl",
"Win32_Networking_WinSock",
"Win32_Security",
"Win32_Security_Credentials",
@@ -0,0 +1,28 @@
+float color_brightness(float3 color) {
+ // REC. 601 luminance coefficients for percieved brightness
+ return dot(color, float3(0.30f, 0.59f, 0.11f));
+}
+
+float light_on_dark_contrast(float enhancedContrast, float3 color) {
+ float brightness = color_brightness(color);
+ float multiplier = saturate(4.0f * (0.75f - brightness));
+ return enhancedContrast * multiplier;
+}
+
+float enhance_contrast(float alpha, float k) {
+ return alpha * (k + 1.0f) / (alpha * k + 1.0f);
+}
+
+float apply_alpha_correction(float a, float b, float4 g) {
+ float brightness_adjustment = g.x * b + g.y;
+ float correction = brightness_adjustment * a + (g.z * b + g.w);
+ return a + a * (1.0f - a) * correction;
+}
+
+float apply_contrast_and_gamma_correction(float sample, float3 color, float enhanced_contrast_factor, float4 gamma_ratios) {
+ float enhanced_contrast = light_on_dark_contrast(enhanced_contrast_factor, color);
+ float brightness = color_brightness(color);
+
+ float contrasted = enhance_contrast(sample, enhanced_contrast);
+ return apply_alpha_correction(contrasted, brightness, gamma_ratios);
+}
@@ -1,3 +1,5 @@
+#include "alpha_correction.hlsl"
+
struct RasterVertexOutput {
float4 position : SV_Position;
float2 texcoord : TEXCOORD0;
@@ -23,17 +25,19 @@ struct Bounds {
int2 size;
};
-Texture2D<float4> t_layer : register(t0);
+Texture2D<float> t_layer : register(t0);
SamplerState s_layer : register(s0);
cbuffer GlyphLayerTextureParams : register(b0) {
Bounds bounds;
float4 run_color;
+ float4 gamma_ratios;
+ float grayscale_enhanced_contrast;
+ float3 _pad;
};
float4 emoji_rasterization_fragment(PixelInput input): SV_Target {
- float3 sampled = t_layer.Sample(s_layer, input.texcoord.xy).rgb;
- float alpha = (sampled.r + sampled.g + sampled.b) / 3;
-
- return float4(run_color.rgb, alpha);
+ float sample = t_layer.Sample(s_layer, input.texcoord.xy).r;
+ float alpha_corrected = apply_contrast_and_gamma_correction(sample, run_color.rgb, grayscale_enhanced_contrast, gamma_ratios);
+ return float4(run_color.rgb, alpha_corrected * run_color.a);
}
@@ -10,12 +10,8 @@ use windows::{
Foundation::*,
Globalization::GetUserDefaultLocaleName,
Graphics::{
- Direct3D::D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP,
- Direct3D11::*,
- DirectWrite::*,
- Dxgi::Common::*,
- Gdi::{IsRectEmpty, LOGFONTW},
- Imaging::*,
+ Direct3D::D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, Direct3D11::*, DirectWrite::*,
+ Dxgi::Common::*, Gdi::LOGFONTW,
},
System::SystemServices::LOCALE_NAME_MAX_LENGTH,
UI::WindowsAndMessaging::*,
@@ -40,12 +36,10 @@ pub(crate) struct DirectWriteTextSystem(RwLock<DirectWriteState>);
struct DirectWriteComponent {
locale: String,
factory: IDWriteFactory5,
- bitmap_factory: AgileReference<IWICImagingFactory>,
in_memory_loader: IDWriteInMemoryFontFileLoader,
builder: IDWriteFontSetBuilder1,
text_renderer: Arc<TextRendererWrapper>,
- render_params: IDWriteRenderingParams3,
gpu_state: GPUState,
}
@@ -76,11 +70,10 @@ struct FontIdentifier {
}
impl DirectWriteComponent {
- pub fn new(bitmap_factory: &IWICImagingFactory, gpu_context: &DirectXDevices) -> Result<Self> {
+ pub fn new(gpu_context: &DirectXDevices) -> Result<Self> {
// todo: ideally this would not be a large unsafe block but smaller isolated ones for easier auditing
unsafe {
let factory: IDWriteFactory5 = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED)?;
- let bitmap_factory = AgileReference::new(bitmap_factory)?;
// The `IDWriteInMemoryFontFileLoader` here is supported starting from
// Windows 10 Creators Update, which consequently requires the entire
// `DirectWriteTextSystem` to run on `win10 1703`+.
@@ -92,36 +85,14 @@ impl DirectWriteComponent {
let locale = String::from_utf16_lossy(&locale_vec);
let text_renderer = Arc::new(TextRendererWrapper::new(&locale));
- let render_params = {
- let default_params: IDWriteRenderingParams3 =
- factory.CreateRenderingParams()?.cast()?;
- let gamma = default_params.GetGamma();
- let enhanced_contrast = default_params.GetEnhancedContrast();
- let gray_contrast = default_params.GetGrayscaleEnhancedContrast();
- let cleartype_level = default_params.GetClearTypeLevel();
- let grid_fit_mode = default_params.GetGridFitMode();
-
- factory.CreateCustomRenderingParams(
- gamma,
- enhanced_contrast,
- gray_contrast,
- cleartype_level,
- DWRITE_PIXEL_GEOMETRY_RGB,
- DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC,
- grid_fit_mode,
- )?
- };
-
let gpu_state = GPUState::new(gpu_context)?;
Ok(DirectWriteComponent {
locale,
factory,
- bitmap_factory,
in_memory_loader,
builder,
text_renderer,
- render_params,
gpu_state,
})
}
@@ -212,11 +183,8 @@ impl GPUState {
}
impl DirectWriteTextSystem {
- pub(crate) fn new(
- gpu_context: &DirectXDevices,
- bitmap_factory: &IWICImagingFactory,
- ) -> Result<Self> {
- let components = DirectWriteComponent::new(bitmap_factory, gpu_context)?;
+ pub(crate) fn new(gpu_context: &DirectXDevices) -> Result<Self> {
+ let components = DirectWriteComponent::new(gpu_context)?;
let system_font_collection = unsafe {
let mut result = std::mem::zeroed();
components
@@ -762,14 +730,14 @@ impl DirectWriteState {
unsafe {
font.font_face.GetRecommendedRenderingMode(
params.font_size.0,
- // The dpi here seems that it has the same effect with `Some(&transform)`
- 1.0,
- 1.0,
+ // Using 96 as scale is applied by the transform
+ 96.0,
+ 96.0,
Some(&transform),
false,
DWRITE_OUTLINE_THRESHOLD_ANTIALIASED,
DWRITE_MEASURING_MODE_NATURAL,
- &self.components.render_params,
+ None,
&mut rendering_mode,
&mut grid_fit_mode,
)?;
@@ -782,8 +750,7 @@ impl DirectWriteState {
rendering_mode,
DWRITE_MEASURING_MODE_NATURAL,
grid_fit_mode,
- // We're using cleartype not grayscale for monochrome is because it provides better quality
- DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE,
+ DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
baseline_origin_x,
baseline_origin_y,
)
@@ -794,10 +761,14 @@ impl DirectWriteState {
fn raster_bounds(&self, params: &RenderGlyphParams) -> Result<Bounds<DevicePixels>> {
let glyph_analysis = self.create_glyph_run_analysis(params)?;
- let bounds = unsafe { glyph_analysis.GetAlphaTextureBounds(DWRITE_TEXTURE_CLEARTYPE_3x1)? };
- // Some glyphs cannot be drawn with ClearType, such as bitmap fonts. In that case
- // GetAlphaTextureBounds() supposedly returns an empty RECT, but I haven't tested that yet.
- if !unsafe { IsRectEmpty(&bounds) }.as_bool() {
+ let bounds = unsafe { glyph_analysis.GetAlphaTextureBounds(DWRITE_TEXTURE_ALIASED_1x1)? };
+
+ if bounds.right < bounds.left {
+ Ok(Bounds {
+ origin: point(0.into(), 0.into()),
+ size: size(0.into(), 0.into()),
+ })
+ } else {
Ok(Bounds {
origin: point(bounds.left.into(), bounds.top.into()),
size: size(
@@ -805,25 +776,6 @@ impl DirectWriteState {
(bounds.bottom - bounds.top).into(),
),
})
- } else {
- // If it's empty, retry with grayscale AA.
- let bounds =
- unsafe { glyph_analysis.GetAlphaTextureBounds(DWRITE_TEXTURE_ALIASED_1x1)? };
-
- if bounds.right < bounds.left {
- Ok(Bounds {
- origin: point(0.into(), 0.into()),
- size: size(0.into(), 0.into()),
- })
- } else {
- Ok(Bounds {
- origin: point(bounds.left.into(), bounds.top.into()),
- size: size(
- (bounds.right - bounds.left).into(),
- (bounds.bottom - bounds.top).into(),
- ),
- })
- }
}
}
@@ -872,13 +824,12 @@ impl DirectWriteState {
glyph_bounds: Bounds<DevicePixels>,
) -> Result<Vec<u8>> {
let mut bitmap_data =
- vec![0u8; glyph_bounds.size.width.0 as usize * glyph_bounds.size.height.0 as usize * 3];
+ vec![0u8; glyph_bounds.size.width.0 as usize * glyph_bounds.size.height.0 as usize];
let glyph_analysis = self.create_glyph_run_analysis(params)?;
unsafe {
glyph_analysis.CreateAlphaTexture(
- // We're using cleartype not grayscale for monochrome is because it provides better quality
- DWRITE_TEXTURE_CLEARTYPE_3x1,
+ DWRITE_TEXTURE_ALIASED_1x1,
&RECT {
left: glyph_bounds.origin.x.0,
top: glyph_bounds.origin.y.0,
@@ -889,30 +840,6 @@ impl DirectWriteState {
)?;
}
- let bitmap_factory = self.components.bitmap_factory.resolve()?;
- let bitmap = unsafe {
- bitmap_factory.CreateBitmapFromMemory(
- glyph_bounds.size.width.0 as u32,
- glyph_bounds.size.height.0 as u32,
- &GUID_WICPixelFormat24bppRGB,
- glyph_bounds.size.width.0 as u32 * 3,
- &bitmap_data,
- )
- }?;
-
- let grayscale_bitmap =
- unsafe { WICConvertBitmapSource(&GUID_WICPixelFormat8bppGray, &bitmap) }?;
-
- let mut bitmap_data =
- vec![0u8; glyph_bounds.size.width.0 as usize * glyph_bounds.size.height.0 as usize];
- unsafe {
- grayscale_bitmap.CopyPixels(
- std::ptr::null() as _,
- glyph_bounds.size.width.0 as u32,
- &mut bitmap_data,
- )
- }?;
-
Ok(bitmap_data)
}
@@ -981,25 +908,24 @@ impl DirectWriteState {
DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC,
DWRITE_MEASURING_MODE_NATURAL,
DWRITE_GRID_FIT_MODE_DEFAULT,
- DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE,
+ DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
baseline_origin_x,
baseline_origin_y,
)
}?;
let color_bounds =
- unsafe { color_analysis.GetAlphaTextureBounds(DWRITE_TEXTURE_CLEARTYPE_3x1) }?;
+ unsafe { color_analysis.GetAlphaTextureBounds(DWRITE_TEXTURE_ALIASED_1x1) }?;
let color_size = size(
color_bounds.right - color_bounds.left,
color_bounds.bottom - color_bounds.top,
);
if color_size.width > 0 && color_size.height > 0 {
- let mut alpha_data =
- vec![0u8; (color_size.width * color_size.height * 3) as usize];
+ let mut alpha_data = vec![0u8; (color_size.width * color_size.height) as usize];
unsafe {
color_analysis.CreateAlphaTexture(
- DWRITE_TEXTURE_CLEARTYPE_3x1,
+ DWRITE_TEXTURE_ALIASED_1x1,
&color_bounds,
&mut alpha_data,
)
@@ -1015,10 +941,6 @@ impl DirectWriteState {
}
};
let bounds = bounds(point(color_bounds.left, color_bounds.top), color_size);
- let alpha_data = alpha_data
- .chunks_exact(3)
- .flat_map(|chunk| [chunk[0], chunk[1], chunk[2], 255])
- .collect::<Vec<_>>();
glyph_layers.push(GlyphLayerTexture::new(
&self.components.gpu_state,
run_color,
@@ -1135,10 +1057,18 @@ impl DirectWriteState {
unsafe { device_context.PSSetSamplers(0, Some(&gpu_state.sampler)) };
unsafe { device_context.OMSetBlendState(&gpu_state.blend_state, None, 0xffffffff) };
+ let crate::FontInfo {
+ gamma_ratios,
+ grayscale_enhanced_contrast,
+ } = DirectXRenderer::get_font_info();
+
for layer in glyph_layers {
let params = GlyphLayerTextureParams {
run_color: layer.run_color,
bounds: layer.bounds,
+ gamma_ratios: *gamma_ratios,
+ grayscale_enhanced_contrast: *grayscale_enhanced_contrast,
+ _pad: [0f32; 3],
};
unsafe {
let mut dest = std::mem::zeroed();
@@ -1298,7 +1228,7 @@ impl GlyphLayerTexture {
Height: texture_size.height as u32,
MipLevels: 1,
ArraySize: 1,
- Format: DXGI_FORMAT_R8G8B8A8_UNORM,
+ Format: DXGI_FORMAT_R8_UNORM,
SampleDesc: DXGI_SAMPLE_DESC {
Count: 1,
Quality: 0,
@@ -1334,7 +1264,7 @@ impl GlyphLayerTexture {
0,
None,
alpha_data.as_ptr() as _,
- (texture_size.width * 4) as u32,
+ texture_size.width as u32,
0,
)
};
@@ -1352,6 +1282,9 @@ impl GlyphLayerTexture {
struct GlyphLayerTextureParams {
bounds: Bounds<i32>,
run_color: Rgba,
+ gamma_ratios: [f32; 4],
+ grayscale_enhanced_contrast: f32,
+ _pad: [f32; 3],
}
struct TextRendererWrapper(pub IDWriteTextRenderer);
@@ -1,4 +1,7 @@
-use std::{mem::ManuallyDrop, sync::Arc};
+use std::{
+ mem::ManuallyDrop,
+ sync::{Arc, OnceLock},
+};
use ::util::ResultExt;
use anyhow::{Context, Result};
@@ -9,6 +12,7 @@ use windows::{
Direct3D::*,
Direct3D11::*,
DirectComposition::*,
+ DirectWrite::*,
Dxgi::{Common::*, *},
},
},
@@ -27,6 +31,11 @@ const RENDER_TARGET_FORMAT: DXGI_FORMAT = DXGI_FORMAT_B8G8R8A8_UNORM;
// This configuration is used for MSAA rendering on paths only, and it's guaranteed to be supported by DirectX 11.
const PATH_MULTISAMPLE_COUNT: u32 = 4;
+pub(crate) struct FontInfo {
+ pub gamma_ratios: [f32; 4],
+ pub grayscale_enhanced_contrast: f32,
+}
+
pub(crate) struct DirectXRenderer {
hwnd: HWND,
atlas: Arc<DirectXAtlas>,
@@ -35,6 +44,7 @@ pub(crate) struct DirectXRenderer {
globals: DirectXGlobalElements,
pipelines: DirectXRenderPipelines,
direct_composition: Option<DirectComposition>,
+ font_info: &'static FontInfo,
}
/// Direct3D objects
@@ -171,6 +181,7 @@ impl DirectXRenderer {
globals,
pipelines,
direct_composition,
+ font_info: Self::get_font_info(),
})
}
@@ -183,10 +194,12 @@ impl DirectXRenderer {
&self.devices.device_context,
self.globals.global_params_buffer[0].as_ref().unwrap(),
&[GlobalParams {
+ gamma_ratios: self.font_info.gamma_ratios,
viewport_size: [
self.resources.viewport[0].Width,
self.resources.viewport[0].Height,
],
+ grayscale_enhanced_contrast: self.font_info.grayscale_enhanced_contrast,
_pad: 0,
}],
)?;
@@ -617,6 +630,52 @@ impl DirectXRenderer {
driver_info: driver_version,
})
}
+
+ pub(crate) fn get_font_info() -> &'static FontInfo {
+ static CACHED_FONT_INFO: OnceLock<FontInfo> = OnceLock::new();
+ CACHED_FONT_INFO.get_or_init(|| unsafe {
+ let factory: IDWriteFactory5 = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED).unwrap();
+ let render_params: IDWriteRenderingParams1 =
+ factory.CreateRenderingParams().unwrap().cast().unwrap();
+ FontInfo {
+ gamma_ratios: Self::get_gamma_ratios(render_params.GetGamma()),
+ grayscale_enhanced_contrast: render_params.GetGrayscaleEnhancedContrast(),
+ }
+ })
+ }
+
+ // Gamma ratios for brightening/darkening edges for better contrast
+ // https://github.com/microsoft/terminal/blob/1283c0f5b99a2961673249fa77c6b986efb5086c/src/renderer/atlas/dwrite.cpp#L50
+ fn get_gamma_ratios(gamma: f32) -> [f32; 4] {
+ const GAMMA_INCORRECT_TARGET_RATIOS: [[f32; 4]; 13] = [
+ [0.0000 / 4.0, 0.0000 / 4.0, 0.0000 / 4.0, 0.0000 / 4.0], // gamma = 1.0
+ [0.0166 / 4.0, -0.0807 / 4.0, 0.2227 / 4.0, -0.0751 / 4.0], // gamma = 1.1
+ [0.0350 / 4.0, -0.1760 / 4.0, 0.4325 / 4.0, -0.1370 / 4.0], // gamma = 1.2
+ [0.0543 / 4.0, -0.2821 / 4.0, 0.6302 / 4.0, -0.1876 / 4.0], // gamma = 1.3
+ [0.0739 / 4.0, -0.3963 / 4.0, 0.8167 / 4.0, -0.2287 / 4.0], // gamma = 1.4
+ [0.0933 / 4.0, -0.5161 / 4.0, 0.9926 / 4.0, -0.2616 / 4.0], // gamma = 1.5
+ [0.1121 / 4.0, -0.6395 / 4.0, 1.1588 / 4.0, -0.2877 / 4.0], // gamma = 1.6
+ [0.1300 / 4.0, -0.7649 / 4.0, 1.3159 / 4.0, -0.3080 / 4.0], // gamma = 1.7
+ [0.1469 / 4.0, -0.8911 / 4.0, 1.4644 / 4.0, -0.3234 / 4.0], // gamma = 1.8
+ [0.1627 / 4.0, -1.0170 / 4.0, 1.6051 / 4.0, -0.3347 / 4.0], // gamma = 1.9
+ [0.1773 / 4.0, -1.1420 / 4.0, 1.7385 / 4.0, -0.3426 / 4.0], // gamma = 2.0
+ [0.1908 / 4.0, -1.2652 / 4.0, 1.8650 / 4.0, -0.3476 / 4.0], // gamma = 2.1
+ [0.2031 / 4.0, -1.3864 / 4.0, 1.9851 / 4.0, -0.3501 / 4.0], // gamma = 2.2
+ ];
+
+ const NORM13: f32 = ((0x10000 as f64) / (255.0 * 255.0) * 4.0) as f32;
+ const NORM24: f32 = ((0x100 as f64) / (255.0) * 4.0) as f32;
+
+ let index = ((gamma * 10.0).round() as usize).clamp(10, 22) - 10;
+ let ratios = GAMMA_INCORRECT_TARGET_RATIOS[index];
+
+ [
+ ratios[0] * NORM13,
+ ratios[1] * NORM24,
+ ratios[2] * NORM13,
+ ratios[3] * NORM24,
+ ]
+ }
}
impl DirectXResources {
@@ -822,8 +881,10 @@ impl DirectXGlobalElements {
#[derive(Debug, Default)]
#[repr(C)]
struct GlobalParams {
+ gamma_ratios: [f32; 4],
viewport_size: [f32; 2],
- _pad: u64,
+ grayscale_enhanced_contrast: f32,
+ _pad: u32,
}
struct PipelineState<T> {
@@ -1544,6 +1605,10 @@ pub(crate) mod shader_resources {
#[cfg(debug_assertions)]
pub(super) fn build_shader_blob(entry: ShaderModule, target: ShaderTarget) -> Result<ID3DBlob> {
unsafe {
+ use windows::Win32::Graphics::{
+ Direct3D::ID3DInclude, Hlsl::D3D_COMPILE_STANDARD_FILE_INCLUDE,
+ };
+
let shader_name = if matches!(entry, ShaderModule::EmojiRasterization) {
"color_text_raster.hlsl"
} else {
@@ -1572,10 +1637,15 @@ pub(crate) mod shader_resources {
let entry_point = PCSTR::from_raw(entry.as_ptr());
let target_cstr = PCSTR::from_raw(target.as_ptr());
+ // really dirty trick because winapi bindings are unhappy otherwise
+ let include_handler = &std::mem::transmute::<usize, ID3DInclude>(
+ D3D_COMPILE_STANDARD_FILE_INCLUDE as usize,
+ );
+
let ret = D3DCompileFromFile(
&HSTRING::from(shader_path.to_str().unwrap()),
None,
- None,
+ include_handler,
entry_point,
target_cstr,
D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION,
@@ -1,7 +1,6 @@
use std::{
cell::RefCell,
ffi::OsStr,
- mem::ManuallyDrop,
path::{Path, PathBuf},
rc::Rc,
sync::Arc,
@@ -18,10 +17,7 @@ use windows::{
UI::ViewManagement::UISettings,
Win32::{
Foundation::*,
- Graphics::{
- Gdi::*,
- Imaging::{CLSID_WICImagingFactory, IWICImagingFactory},
- },
+ Graphics::Gdi::*,
Security::Credentials::*,
System::{Com::*, LibraryLoader::*, Ole::*, SystemInformation::*, Threading::*},
UI::{Input::KeyboardAndMouse::*, Shell::*, WindowsAndMessaging::*},
@@ -41,7 +37,6 @@ pub(crate) struct WindowsPlatform {
foreground_executor: ForegroundExecutor,
text_system: Arc<DirectWriteTextSystem>,
windows_version: WindowsVersion,
- bitmap_factory: ManuallyDrop<IWICImagingFactory>,
drop_target_helper: IDropTargetHelper,
validation_number: usize,
main_thread_id_win32: u32,
@@ -101,12 +96,8 @@ impl WindowsPlatform {
let foreground_executor = ForegroundExecutor::new(dispatcher);
let directx_devices = DirectXDevices::new(disable_direct_composition)
.context("Unable to init directx devices.")?;
- let bitmap_factory = ManuallyDrop::new(unsafe {
- CoCreateInstance(&CLSID_WICImagingFactory, None, CLSCTX_INPROC_SERVER)
- .context("Error creating bitmap factory.")?
- });
let text_system = Arc::new(
- DirectWriteTextSystem::new(&directx_devices, &bitmap_factory)
+ DirectWriteTextSystem::new(&directx_devices)
.context("Error creating DirectWriteTextSystem")?,
);
let drop_target_helper: IDropTargetHelper = unsafe {
@@ -128,7 +119,6 @@ impl WindowsPlatform {
text_system,
disable_direct_composition,
windows_version,
- bitmap_factory,
drop_target_helper,
validation_number,
main_thread_id_win32,
@@ -716,7 +706,6 @@ impl Platform for WindowsPlatform {
impl Drop for WindowsPlatform {
fn drop(&mut self) {
unsafe {
- ManuallyDrop::drop(&mut self.bitmap_factory);
OleUninitialize();
}
}
@@ -1,6 +1,10 @@
+#include "alpha_correction.hlsl"
+
cbuffer GlobalParams: register(b0) {
+ float4 gamma_ratios;
float2 global_viewport_size;
- uint2 _pad;
+ float grayscale_enhanced_contrast;
+ uint _pad;
};
Texture2D<float4> t_sprite: register(t0);
@@ -1098,7 +1102,8 @@ MonochromeSpriteVertexOutput monochrome_sprite_vertex(uint vertex_id: SV_VertexI
float4 monochrome_sprite_fragment(MonochromeSpriteFragmentInput input): SV_Target {
float sample = t_sprite.Sample(s_sprite, input.tile_position).r;
- return float4(input.color.rgb, input.color.a * sample);
+ float alpha_corrected = apply_contrast_and_gamma_correction(sample, input.color.rgb, grayscale_enhanced_contrast, gamma_ratios);
+ return float4(input.color.rgb, input.color.a * alpha_corrected);
}
/*