AdaptExposureCS.hlsl 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. // RUN: %dxc -E main -T cs_6_0 %s | FileCheck %s
  2. // CHECK: flattenedThreadIdInGroup
  3. // CHECK: barrier
  4. // CHECK: addrspace(3)
  5. // CHECK: barrier
  6. // CHECK: FMax
  7. // CHECK: Exp
  8. // CHECK: FMin
  9. // CHECK: Round_ni
  10. // CHECK: FAbs
  11. //
  12. // Copyright (c) Microsoft. All rights reserved.
  13. // This code is licensed under the MIT License (MIT).
  14. // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
  15. // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
  16. // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
  17. // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
  18. //
  19. // Developed by Minigraph
  20. //
  21. // Author: James Stanard
  22. //
  23. // The group size is 16x16, but one group iterates over an entire 16-wide column of pixels (384 pixels tall)
  24. // Assuming the total workspace is 640x384, there will be 40 thread groups computing the histogram in parallel.
  25. // The histogram measures logarithmic luminance ranging from 2^-12 up to 2^4. This should provide a nice window
  26. // where the exposure would range from 2^-4 up to 2^4.
  27. #include "PostEffectsRS.hlsli"
  28. ByteAddressBuffer Histogram : register(t0);
  29. RWStructuredBuffer<float> Exposure : register(u0);
  30. cbuffer cb0 : register(b1)
  31. {
  32. float TargetLuminance;
  33. float AdaptationRate;
  34. float MinExposure;
  35. float MaxExposure;
  36. float PeakIntensity;
  37. float PixelCount;
  38. }
  39. groupshared float gs_Accum[256];
  40. [RootSignature(PostEffects_RootSig)]
  41. [numthreads( 256, 1, 1 )]
  42. void main( uint GI : SV_GroupIndex )
  43. {
  44. float WeightedSum = (float)GI * (float)Histogram.Load(GI * 4);
  45. [unroll]
  46. for (uint i = 1; i < 256; i *= 2)
  47. {
  48. gs_Accum[GI] = WeightedSum; // Write
  49. GroupMemoryBarrierWithGroupSync(); // Sync
  50. WeightedSum += gs_Accum[(GI + i) % 256]; // Read
  51. GroupMemoryBarrierWithGroupSync(); // Sync
  52. }
  53. float MinLog = Exposure[4];
  54. float MaxLog = Exposure[5];
  55. float LogRange = Exposure[6];
  56. float RcpLogRange = Exposure[7];
  57. // Average histogram value is the weighted sum of all pixels divided by the total number of pixels
  58. // minus those pixels which provided no weight (i.e. black pixels.)
  59. float weightedHistAvg = WeightedSum / (max(1, PixelCount - Histogram.Load(0))) - 1.0;
  60. float logAvgLuminance = exp2(weightedHistAvg * LogRange / 254.0 + MinLog);
  61. float targetExposure = TargetLuminance / logAvgLuminance;
  62. float exposure = Exposure[0];
  63. exposure = lerp(exposure, targetExposure, AdaptationRate);
  64. exposure = clamp(exposure, MinExposure, MaxExposure);
  65. if (GI == 0)
  66. {
  67. Exposure[0] = exposure;
  68. Exposure[1] = 1.0 / exposure;
  69. Exposure[2] = exposure / PeakIntensity;
  70. Exposure[3] = weightedHistAvg;
  71. // First attempt to recenter our histogram around the log-average.
  72. float biasToCenter = (floor(weightedHistAvg) - 128.0) / 255.0;//
  73. if (abs(biasToCenter) > 0.1)
  74. {
  75. MinLog += biasToCenter * RcpLogRange;
  76. MaxLog += biasToCenter * RcpLogRange;
  77. }
  78. // TODO: Increase or decrease the log range to better fit the range of values.
  79. // (Idea) Look at intermediate log-weighted sums for under- or over-represented
  80. // extreme bounds. I.e. break the for loop into two pieces to compute the sum of
  81. // groups of 16, check the groups on each end, then finish the recursive summation.
  82. Exposure[4] = MinLog;
  83. Exposure[5] = MaxLog;
  84. Exposure[6] = LogRange;
  85. Exposure[7] = 1.0 / LogRange;
  86. }
  87. }