@@ -37,26 +37,41 @@ namespace ShaderLab::Effects
3737 // -----------------------------------------------------------------------
3838
3939 static const std::string s_luminanceHeatmapHLSL = R"HLSL(
40- // Luminance Heatmap - false-color visualization of luminance
41- Texture2D Source : register(t0);
40+ // Luminance Heatmap -- D3D11 compute, false-color luminance visualization.
41+ // MinNits / MaxNits are gpuBindable so a Luminance Statistics .Min / .Max
42+ // can drive the heatmap range automatically per source-distribution
43+ // without a CPU readback round-trip.
44+ #include "shaderlab_params.hlsli"
45+
46+ Texture2D<float4> Source : register(t0);
47+ RWTexture2D<float4> ImageOutput : register(u1);
48+
49+ SHADERLAB_GPU_BUFFER(MinNits, t1)
50+ SHADERLAB_GPU_BUFFER(MaxNits, t2)
4251
4352cbuffer constants : register(b0) {
44- float MinNits; // default 0.0
45- float MaxNits; // default 10000.0
46- uint ColormapMode; // 0=Turbo, 1=Inferno
53+ uint Width;
54+ uint Height;
55+ SHADERLAB_PARAM(float, MinNits) // default 0.0
56+ SHADERLAB_PARAM(float, MaxNits) // default 10000.0
57+ uint ColormapMode; // 0=Turbo, 1=Inferno
4758};
4859
49- float4 main(
50- float4 pos : SV_POSITION,
51- float4 uv0 : TEXCOORD0) : SV_TARGET
60+ [numthreads(8, 8, 1)]
61+ void main(uint3 dtid : SV_DispatchThreadID)
5262{
53- float4 color = Source.Load(int3(uv0.xy, 0));
63+ if (dtid.x >= Width || dtid.y >= Height) return;
64+
65+ SHADERLAB_LOAD_PARAM(float, MinNits)
66+ SHADERLAB_LOAD_PARAM(float, MaxNits)
67+
68+ float4 color = Source.Load(int3(dtid.xy, 0));
5469 float nits = ScRGBLuminanceNits(color.rgb);
5570 float t = saturate((nits - MinNits) / max(MaxNits - MinNits, 0.001));
5671 float3 mapped = TurboColormap(t);
57- // Turbo colormap outputs perceptual 0-1 values.
58- // Keep as-is in scRGB (1.0 = 80 nits SDR white) for visible display.
59- return float4(mapped, color.a);
72+ // Turbo colormap outputs perceptual 0-1 values; keep in scRGB
73+ // (1.0 = 80 nits SDR white) for visible display.
74+ ImageOutput[dtid.xy] = float4(mapped, color.a);
6075}
6176)HLSL" ;
6277
@@ -137,39 +152,52 @@ float4 main(
137152)HLSL" ;
138153
139154 static const std::string s_luminanceHighlightHLSL = R"HLSL(
140- // Luminance Highlight
141- // Mirrors Gamut Highlight: pixels whose luminance falls outside the
142- // active nit range (or inside, depending on Mode) are tinted with an
143- // overlay color.
155+ // Luminance Highlight -- D3D11 compute, mirrors Gamut Highlight but on
156+ // luminance. Pixels whose luminance falls outside (or inside, per Mode)
157+ // the active nit range are tinted with an overlay color.
158+ //
159+ // MinNits / MaxNits are gpuBindable so a Luminance Statistics .Min / .Max
160+ // (or Working Space.MinNits / .PeakNits) can drive the range
161+ // automatically without a CPU readback round-trip.
144162//
145163// TargetRange selects the [min,max] nit window:
146164// 0 = SDR (0 .. 80 nits)
147165// 1 = HDR 400 (0 .. 400 nits)
148166// 2 = HDR 1000 (0 .. 1000 nits)
149167// 3 = HDR 4000 (0 .. 4000 nits)
150168// 4 = HDR 10000 (0 .. 10000 nits)
151- // 5 = Custom (use MinNits / MaxNits sliders directly; bind
152- // to `Working Space.MinNits/PeakNits` for
153- // monitor-matched analysis.)
154- Texture2D Source : register(t0);
169+ // 5 = Custom (use MinNits / MaxNits sliders directly)
170+ #include "shaderlab_params.hlsli"
171+
172+ Texture2D<float4> Source : register(t0);
173+ RWTexture2D<float4> ImageOutput : register(u1);
174+
175+ SHADERLAB_GPU_BUFFER(MinNits, t1)
176+ SHADERLAB_GPU_BUFFER(MaxNits, t2)
155177
156178cbuffer constants : register(b0) {
157- uint TargetRange;
158- float MinNits;
159- float MaxNits;
179+ uint Width;
180+ uint Height;
181+ uint TargetRange;
182+ SHADERLAB_PARAM(float, MinNits)
183+ SHADERLAB_PARAM(float, MaxNits)
160184 float OverlayR;
161185 float OverlayG;
162186 float OverlayB;
163187 float OverlayStrength;
164- uint Mode; // 0 = Out-of-Range, 1 = In-Range
188+ uint Mode; // 0 = Out-of-Range, 1 = In-Range
165189};
166190
167- float4 main(
168- float4 pos : SV_POSITION,
169- float4 uv0 : TEXCOORD0) : SV_TARGET
191+ [numthreads(8, 8, 1)]
192+ void main(uint3 dtid : SV_DispatchThreadID)
170193{
171- float4 color = Source.Load(int3(uv0.xy, 0));
172- if (color.a < 0.001) return color;
194+ if (dtid.x >= Width || dtid.y >= Height) return;
195+
196+ SHADERLAB_LOAD_PARAM(float, MinNits)
197+ SHADERLAB_LOAD_PARAM(float, MaxNits)
198+
199+ float4 color = Source.Load(int3(dtid.xy, 0));
200+ if (color.a < 0.001) { ImageOutput[dtid.xy] = color; return; }
173201
174202 // ScRGBLuminanceNits: scRGB luminance * 80 (1.0 = 80 nits SDR white).
175203 float nits = ScRGBLuminanceNits(color.rgb);
@@ -192,14 +220,13 @@ float4 main(
192220 effMax = MaxNits;
193221 }
194222
195- // Defensive: degenerate range collapses to "everything out-of-range".
196223 bool outOfRange = (effMin >= effMax) || (nits < effMin) || (nits > effMax);
197224 bool highlight = (Mode > 0.5) ? !outOfRange : outOfRange;
198225 if (highlight) {
199226 float3 overlay = float3(OverlayR, OverlayG, OverlayB);
200227 color.rgb = lerp(color.rgb, overlay, OverlayStrength);
201228 }
202- return color;
229+ ImageOutput[dtid.xy] = color;
203230}
204231)HLSL" ;
205232
@@ -307,19 +334,24 @@ float4 main(
307334 const auto & colorMath = GetColorMathHLSL ();
308335
309336 // ---- Luminance Heatmap ----
337+ // D3D11 compute -- MinNits / MaxNits gpuBindable.
310338 {
311339 ShaderLabEffectDescriptor desc;
312340 desc.name = L" Luminance Heatmap" ;
313- desc.effectId = L" Luminance Heatmap" ; desc.effectVersion = 2 ;
341+ desc.effectId = L" Luminance Heatmap" ; desc.effectVersion = 3 ;
314342 desc.category = L" Analysis" ;
315343 desc.subcategory = L" Highlights" ;
316- desc.shaderType = Graph::CustomShaderType::PixelShader;
344+ desc.shaderType = Graph::CustomShaderType::D3D11ComputeShader;
345+ desc.hasImageOutput = true ;
346+ desc.threadGroupX = 8 ;
347+ desc.threadGroupY = 8 ;
348+ desc.threadGroupZ = 1 ;
317349 desc.hlslSource = colorMath + s_luminanceHeatmapHLSL;
318350 desc.inputNames = { L" Source" };
319351 desc.parameters = {
320- { L" MinNits" , L" float" , 0 .0f , 0 .0f , 10000 .0f , 1 .0f },
321- { L" MaxNits" , L" float" , 10000 .0f , 0 .0f , 10000 .0f , 100 .0f },
322- { L" ColormapMode" , L" float" , 0 .0f , 0 .0f , 1 .0f , 1 .0f , { L" Turbo" , L" Inferno" } },
352+ Graph::ParameterDefinition { L" MinNits" , L" float" , 0 .0f , 0 .0f , 10000 .0f , 1 .0f , {}, L" " , true },
353+ Graph::ParameterDefinition { L" MaxNits" , L" float" , 10000 .0f , 0 .0f , 10000 .0f , 100 .0f , {}, L" " , true },
354+ Graph::ParameterDefinition { L" ColormapMode" , L" float" , 0 .0f , 0 .0f , 1 .0f , 1 .0f , { L" Turbo" , L" Inferno" } },
323355 };
324356 m_effects.push_back (std::move (desc));
325357 }
@@ -363,18 +395,22 @@ float4 main(
363395 {
364396 ShaderLabEffectDescriptor desc;
365397 desc.name = L" Luminance Highlight" ;
366- desc.effectId = L" Luminance Highlight" ; desc.effectVersion = 5 ;
398+ desc.effectId = L" Luminance Highlight" ; desc.effectVersion = 6 ;
367399 desc.category = L" Analysis" ;
368400 desc.subcategory = L" Highlights" ;
369- desc.shaderType = Graph::CustomShaderType::PixelShader;
401+ desc.shaderType = Graph::CustomShaderType::D3D11ComputeShader;
402+ desc.hasImageOutput = true ;
403+ desc.threadGroupX = 8 ;
404+ desc.threadGroupY = 8 ;
405+ desc.threadGroupZ = 1 ;
370406 desc.hlslSource = colorMath + s_luminanceHighlightHLSL;
371407 desc.inputNames = { L" Source" };
372408 desc.parameters = {
373409 { L" TargetRange" , L" float" , 0 .0f , 0 .0f , 5 .0f , 1 .0f ,
374410 { L" SDR (0-80)" , L" HDR 400" , L" HDR 1000" , L" HDR 4000" ,
375411 L" HDR 10000" , L" Custom" } },
376- { L" MinNits" , L" float" , 0 .0f , 0 .0f , 10000 .0f , 1 .0f , {}, L" TargetRange == 5" },
377- { L" MaxNits" , L" float" , 1000 .0f , 0 .0f , 10000 .0f , 10 .0f , {}, L" TargetRange == 5" },
412+ Graph::ParameterDefinition { L" MinNits" , L" float" , 0 .0f , 0 .0f , 10000 .0f , 1 .0f , {}, L" TargetRange == 5" , true },
413+ Graph::ParameterDefinition { L" MaxNits" , L" float" , 1000 .0f , 0 .0f , 10000 .0f , 10 .0f , {}, L" TargetRange == 5" , true },
378414 { L" OverlayR" , L" float" , 1 .0f , 0 .0f , 1 .0f , 0 .01f },
379415 { L" OverlayG" , L" float" , 0 .0f , 0 .0f , 1 .0f , 0 .01f },
380416 { L" OverlayB" , L" float" , 1 .0f , 0 .0f , 1 .0f , 0 .01f },
@@ -2334,47 +2370,66 @@ float4 main(float4 pos : SV_POSITION, float2 uv : TEXCOORD) : SV_Target
23342370 // multiplier ramps from 1 toward (1 - Amount); above PeakNits
23352371 // the saturation is fully attenuated. Pairs naturally with
23362372 // ICtCp Tone Map: tone-map first, then desat the highlights.
2373+ // D3D11 compute -- KneeNits + PeakNits gpuBindable (typical
2374+ // bindings: LumStats.P95 -> KneeNits, LumStats.Max -> PeakNits).
23372375 {
23382376 static const std::string ictcpHighlightDesatHLSL = R"HLSL(
2339- // ICtCp Highlight Desaturation — smooth Ct/Cp rolloff vs. I
2340- Texture2D Source : register(t0);
2341- SamplerState Sampler : register(s0);
2377+ // ICtCp Highlight Desaturation -- D3D11 compute, smooth Ct/Cp rolloff vs. I.
2378+ #include "shaderlab_params.hlsli"
2379+
2380+ Texture2D<float4> Source : register(t0);
2381+ RWTexture2D<float4> ImageOutput : register(u1);
2382+
2383+ SHADERLAB_GPU_BUFFER(KneeNits, t1)
2384+ SHADERLAB_GPU_BUFFER(PeakNits, t2)
23422385
23432386cbuffer constants : register(b0) {
2344- float KneeNits; // start of the rolloff (e.g. 200)
2345- float PeakNits; // end of the rolloff (e.g. 1000)
2346- float Amount; // [0..1], how far to desaturate at peak (1 = grayscale at peak)
2387+ uint Width;
2388+ uint Height;
2389+ SHADERLAB_PARAM(float, KneeNits) // start of the rolloff (e.g. 200)
2390+ SHADERLAB_PARAM(float, PeakNits) // end of the rolloff (e.g. 1000)
2391+ float Amount; // [0..1] how far to desaturate at peak
23472392};
23482393
2349- float4 main(float4 pos : SV_POSITION, float2 uv : TEXCOORD) : SV_Target
2394+ [numthreads(8, 8, 1)]
2395+ void main(uint3 dtid : SV_DispatchThreadID)
23502396{
2351- float4 color = Source.Load(int3(uv, 0));
2397+ if (dtid.x >= Width || dtid.y >= Height) return;
2398+
2399+ SHADERLAB_LOAD_PARAM(float, KneeNits)
2400+ SHADERLAB_LOAD_PARAM(float, PeakNits)
2401+
2402+ float4 color = Source.Load(int3(dtid.xy, 0));
23522403 float3 ictcp = ScRGBToICtCp(color.rgb);
23532404
2354- // Map I (PQ) back to nits so the user's parameters mean what they say
2355- // even though the I axis is non-linear.
2405+ // Map I (PQ) back to nits so the user's parameters mean what they
2406+ // say even though the I axis is non-linear.
23562407 float nits = IToNits(ictcp.x);
23572408 float t = saturate((nits - KneeNits) / max(PeakNits - KneeNits, 1e-3));
23582409 float scale = 1.0 - saturate(Amount) * smoothstep(0.0, 1.0, t);
23592410
23602411 ictcp.y *= scale;
23612412 ictcp.z *= scale;
23622413 float3 outRgb = ICtCpToScRGB(ictcp);
2363- return float4(outRgb, color.a);
2414+ ImageOutput[dtid.xy] = float4(outRgb, color.a);
23642415}
23652416)HLSL" ;
23662417 ShaderLabEffectDescriptor desc;
23672418 desc.name = L" ICtCp Highlight Desaturation" ;
2368- desc.effectId = L" ICtCp Highlight Desaturation" ; desc.effectVersion = 3 ;
2419+ desc.effectId = L" ICtCp Highlight Desaturation" ; desc.effectVersion = 4 ;
23692420 desc.category = L" Analysis" ;
23702421 desc.subcategory = L" Tone Mapping" ;
2371- desc.shaderType = Graph::CustomShaderType::PixelShader;
2422+ desc.shaderType = Graph::CustomShaderType::D3D11ComputeShader;
2423+ desc.hasImageOutput = true ;
2424+ desc.threadGroupX = 8 ;
2425+ desc.threadGroupY = 8 ;
2426+ desc.threadGroupZ = 1 ;
23722427 desc.hlslSource = colorMath + ictcpHighlightDesatHLSL;
23732428 desc.inputNames = { L" Source" };
23742429 desc.parameters = {
2375- { L" KneeNits" , L" float" , 200 .0f , 10 .0f , 5000 .0f , 10 .0f },
2376- { L" PeakNits" , L" float" , 1000 .0f , 50 .0f , 10000 .0f , 50 .0f },
2377- { L" Amount" , L" float" , 1 .0f , 0 .0f , 1 .0f , 0 .05f },
2430+ Graph::ParameterDefinition { L" KneeNits" , L" float" , 200 .0f , 10 .0f , 5000 .0f , 10 .0f , {}, L" " , true },
2431+ Graph::ParameterDefinition { L" PeakNits" , L" float" , 1000 .0f , 50 .0f , 10000 .0f , 50 .0f , {}, L" " , true },
2432+ { L" Amount" , L" float" , 1 .0f , 0 .0f , 1 .0f , 0 .05f },
23782433 };
23792434 m_effects.push_back (std::move (desc));
23802435 }
0 commit comments