protected override ITextureFilter CreateFilter(ITextureFilter input) { if (Renderer.InputFormat.IsRgb()) { return(input); } int bits = Renderer.InputFormat.GetBitDepth(); if (bits > MaxBitDepth) { return(input); } float[] consts = { (1 << bits) - 1, Power }; var Downscale = new Shader(FromFile("Downscale.hlsl")) { Transform = s => new TextureSize(s.Width / 2, s.Height / 2), Arguments = consts }; var DownscaleLuma = new Shader(FromFile("DownscaleLuma.hlsl")) { SizeIndex = 1, Arguments = consts }; DownscaleLuma["iteration"] = 0; var Deband = new Shader(FromFile("Deband.hlsl", compilerOptions: PreserveDetail ? "PRESERVE_DETAIL=1" : "")) { Arguments = consts, LinearSampling = false, SizeIndex = 1 }; var pyramid = new Stack <ITextureFilter>(); var composition = input as ICompositionFilter; if (composition != null) { pyramid.Push(composition.Luma); pyramid.Push(DownscaleLuma.ApplyTo(composition.Luma, composition.Chroma)); } else { pyramid.Push(input.ConvertToYuv()); } // Build gaussian pyramid while (pyramid.Peek().Size().Width >= 2 && pyramid.Peek().Size().Height >= 2) { Downscale["iteration"] = pyramid.Count - 1; pyramid.Push(Downscale.ApplyTo(pyramid.Peek())); } // Process pyramid ITextureFilter chroma = null; ITextureFilter result = pyramid.Peek(); while (pyramid.Count > 1) { if (composition != null && pyramid.Count == 2) { chroma = result; Deband.Format = TextureFormat.Unorm16_R; } result = Deband.ApplyTo(pyramid.Pop(), pyramid.Peek(), result); } if (composition != null) { return(result.ComposeWith(chroma, copyParametersFrom: composition)); } else { return(result.ConvertToRgb()); } }