dotnet / dotnet/dotnet-api-docs
Document that PixelShader textures are internally converted to pBGRA
- Dominant language
- C#
- Stars
- 949
- Forks
- 1.7k
- Avg merge
- 3d 27m
- Merged PRs (30d)
- 49
Description
---
**Issue moved from MicrosoftDocs/feedback#3862**
- Please respond to @Niko-O.
---
_From @Niko-O on Sunday, November 6, 2022 11:53:24 PM_
**Is your feature request related to a problem? Please describe.**
I am passing a WritableBitmap to a ShaderEffect's PixelShader, with its PixelFormat being Gray32Float because I need more precision than 256 different values. I am seeing artefacts caused by a lack of said precision. After two afternoons of troubleshooting I found [this random forum post](https://social.msdn.microsoft.com/Forums/vstudio/en-US/6a683117-0232-45e6-875a-56aa922d9de9/debugging-pixel-shaders-for-wpf-effects#72743856-33cd-4f7a-9885-b8078f8bbeec):
> WPF doesn't support different pixel formats as inputs to shaders. Internally, everything we render is converted to 32-bit pBGRA (pre-multiplied alpha), so every input sampler to the ShaderEffects will use that format.
Nothing in the [documentation of the ShaderEffect class](https://learn.microsoft.com/en-us/dotnet/api/system.windows.media.effects.shadereffect?view=windowsdesktop-6.0) or [its RegisterPixelShaderSamplerProperty method](https://learn.microsoft.com/en-us/dotnet/api/system.windows.media.effects.shadereffect.registerpixelshadersamplerproperty?view=windowsdesktop-6.0#system-windows-media-effects-shadereffect-registerpixelshadersamplerproperty(system-string-system-type-system-int32)) indicates that this would happen!
**Describe the solution you'd like**
It's somewhat understandable that this happens to the implicit input sampler `register(S0)`. I can imagine that it simplifies WPF's internal rendering code a lot. But I can't think of a good reason as to why it would happen with the other samplers as well. AFAIK those textures are passed straight into the pixel shader, so there should be no need to mangle them.
Ideally, WPF would provide a way to keep the data untouched, but I assume that won't happen any time soon. In the meantime, this behavior should be clearly documented in both the `RegisterPixelShaderSamplerProperty` function and the `ShaderEffect` class.
**Describe alternatives you've considered**
I changed the WritableBitmap's PixelFormat to BGR24 and mangled the float values into that. Pseudocode:
Assuming V starts out from 0 inclusive to 1 exclusive:
```
T *= 256
B = truncate(T)
T -= B
T *= 256
G = truncate(T)
T -= G
T *= 256
R = truncate(T)
```
And glue those together with `B + G / 256 + R / 256 / 256;` in the shader (R, G and B are already effectively divided by 256).
**Additional context**
Simple test shader:
TestTexture is an ImageBrush with a WritableBitmap of size ViewportWidth by 1, with pixel (0, 0) being set to 0.0, pixel (ViewportWidth-1, 0) being set to 1.0, and pixels in-between linearly interpolated. ViewportWidth and ViewportHeight are the size (in pixels) of the UIElement that has this ShaderEffect applied.
```
sampler2D TestTexture : register(S1);
float ViewportHeight : register(C1);
float Line(float TextureValue, float Y)
{
return saturate(1 - abs(TextureValue - Y) * ViewportHeight / 4);
}
float DecodeRgbFloat(float3 RGB)
{
return RGB.b + RGB.g / 256 + RGB.r / 256 / 256;
}
float4 main(float2 UV : TEXCOORD) : SV_Target
{
return float4(Line( tex2D(TestTexture, float2(UV.x, 0)).r , 1 - UV.y), 0, 0, 1); // For first graph, with Gray32Float
return float4(Line(DecodeRgbFloat(tex2D(TestTexture, float2(UV.x, 0)).rgb), 1 - UV.y), 0, 0, 1); // For second graph, with Bgr24
}
```
This shader graphs the actual value of the texture. X-axis is the texture's U-coordinate, Y-axis is the texture's color value (red channel in this case) at (X, 0).

Note the very pronounced stair-stepping! (Also, it's not linear because Gray32Float uses a Gamma value of 2.2, even though it's documented to not do that. But that's a separate issue. The problem is the stair-stepping.)
Using `DecodeRgbFloat` and the mangled Bgr24 format instead, the line is perfectly smooth:

Contributor guide
Assessment
This issue has not been assessed yet.