Advertisement
Guest User

The Witcher 3 - average log luminance calculation 1.0

a guest
Dec 15th, 2018
527
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.11 KB | None | 0 0
  1. cbuffer cbPerFrame : register (b0)
  2. {
  3. float4 cb0_v0; // xy - downscaled buffer size, zw - start/end params
  4. }
  5.  
  6. RWStructuredBuffer<uint> g_buffer : register (u0);
  7. RWTexture2D<float> g_avgLuminance : register (u1);
  8.  
  9. groupshared uint shared_data[256];
  10. // There is one thread group has 64 threads and shared storage (shared_data)
  11. [numthreads(64, 1, 1)]
  12. void TestCS(uint3 GTid : SV_GroupThreadID)
  13. {
  14. // GroupThreadID: Number of currently processed thread within a single thread group.
  15. // In this case values of threadID range [0-63]
  16. const uint threadID = GTid.x;
  17.  
  18. // The first step is to set whole shared data with data from previous stage.
  19. // Because each thread group has 64 threads, each one can fill 4 elements in one thread
  20. // using a simple offset.
  21. [unroll] for (uint idx=0; idx < 4; idx++)
  22. {
  23. const uint offset = threadID + idx*64;
  24.  
  25. shared_data[ offset ] = g_buffer[offset];
  26. }
  27.  
  28. // We set a barrier here, which means we block execution of all threads in a group until all group
  29. // shared accesses have been completed and all threads in the group have reached this call.
  30. GroupMemoryBarrierWithGroupSync();
  31.  
  32. // Perform calculations only with the thread with '0' index.
  33. [branch] if (threadID == 0)
  34. {
  35. // Total number of pixels in downscaled buffer
  36. uint fTotalPixels = cb0_v0.x * cb0_v0.y;
  37.  
  38. // Start number of pixels we want to incorporate in average luminance calculation
  39. int pixelsToConsiderStart = fTotalPixels * cb0_v0.z;
  40. int pixelsToConsiderEnd = fTotalPixels * cb0_v0.w;
  41.  
  42. int pixelsMinusOne = fTotalPixels - 1;
  43.  
  44. pixelsToConsiderStart = clamp( pixelsToConsiderStart, 0, pixelsMinusOne );
  45. pixelsToConsiderEnd = clamp( pixelsToConsiderEnd, pixelsToConsiderStart, pixelsMinusOne );
  46.  
  47. // Number of already processed pixels
  48. int numProcessedPixels = 0;
  49.  
  50. // Luma cell [0-255]
  51. int lumaValue = 0;
  52.  
  53. // Whether to continue execution of loop
  54. bool bExitLoop = false;
  55.  
  56. // The purpose of the first loop is to omit "pixelsToConsiderStart" pixels.
  57. // We keep number of omitted pixels from previous cells and lumaValue to use in the next loop.
  58. //
  59. // For example:
  60. // * pixelsToConsiderStart = 33000
  61. // * In the first pass of loop, shared_data[0] has 37000 pixels, which exits the loop
  62. // The output from the loop are:
  63. // numProcessedPixels = 0 (33000 pixels should have been ommitted, but 4000 pixels must be taken into consideration)
  64. // lumaValue = 0 (because 4000 pixels left in shared_data[0], we will start calculating total luminance from
  65. // exactly that point)
  66. [loop]
  67. while (!bExitLoop)
  68. {
  69. // Get number of pixels with specific luma value.
  70. uint numPixels = shared_data[lumaValue];
  71.  
  72. // Check how many pixels we would have with lumaValue
  73. int tempSum = numProcessedPixels + numPixels;
  74.  
  75. // If more than pixelsToConsiderStart, exit the loop.
  76. // Therefore, we will start calculating luminance from lumaValue.
  77. // Simply speaking, pixelsToConsiderStart is number of "darken" pixels to omit before starting calculation.
  78. [flatten]
  79. if (tempSum > pixelsToConsiderStart)
  80. {
  81. bExitLoop = true;
  82. }
  83. else
  84. {
  85. numProcessedPixels = tempSum;
  86. lumaValue++;
  87. }
  88. }
  89.  
  90.  
  91. float finalAvgLuminance = 0.0f;
  92.  
  93. // Number of omitted pixels in the first loop
  94. uint numProcessedPixelStart = numProcessedPixels;
  95.  
  96. // The purpose of this loop is to calculate contribution of pixels and average luminance.
  97. // We start from point calculated in the previous loop, keeping number of omitted pixels and starting lumaValue positon.
  98. // We decode luma value from [0-255] range, multiply it by number of pixels which have this specific luma, and sum it up until
  99. // we process pixelsToConsiderEnd pixels.
  100. // After that, we divide total contribution by number of analyzed pixels.
  101. bExitLoop = false;
  102. [loop]
  103. while (!bExitLoop)
  104. {
  105. // Get number of pixels with specific luma value.
  106. uint numPixels = shared_data[lumaValue];
  107.  
  108. // Add to all processed pixels
  109. numProcessedPixels += numPixels;
  110.  
  111. // Currently processed luma, distributed in [0-255] range (uint)
  112. uint encodedLumaUint = lumaValue;
  113.  
  114. // Number of pixels with currently processed luma
  115. float numberOfPixelsWithCurrentLuma = numPixels;
  116.  
  117. // Currently processed, encoded [0-255] luma (float)
  118. float encodedLumaFloat = encodedLumaUint;
  119.  
  120.  
  121. // Reconstruct encodedLumaFloat by inversing encoding process from the first (distribution) pass,
  122. // which was:
  123. //
  124. // float luma = dot(hdrPixelColor, LUMA_RGB);
  125. // float outLuma;
  126. //
  127. // outLuma = luma + 1.0; // because log(0) is undef and log(1) = 0
  128. // outLuma = log( outLuma ) // logarithmically distribute
  129. // outLuma = outLuma * 128 // scale by 128, which means log(1) * 128 = 0, log(2,71828) * 128 = 128,
  130. // log(7,38905) * 128 = 256
  131.  
  132. // we start by adding half (we don't want to have zero)
  133. float fDecodedLuma = encodedLumaFloat + 0.5;
  134.  
  135. // and decode luminance
  136. fDecodedLuma /= 128.0; // Divide by 128
  137. fDecodedLuma = exp(fDecodedLuma); // exp(x) which cancels log(x)
  138. fDecodedLuma -= 1.0; // Subtract 1.0
  139.  
  140. // Calculate contribution of this luma
  141. float fCurrentLumaContribution = numberOfPixelsWithCurrentLuma * fDecodedLuma;
  142.  
  143. // (Temporary) contribution from all previous passes and current one.
  144. float tempTotalContribution = fCurrentLumaContribution + finalAvgLuminance;
  145.  
  146.  
  147. [flatten]
  148. if (numProcessedPixels > pixelsToConsiderEnd )
  149. {
  150. // to exit the loop
  151. bExitLoop = true;
  152.  
  153. // We already processed all pixels we wanted, so perform final division here.
  154. // Number of all processed pixels from user-selected start
  155. int diff = numProcessedPixels - numProcessedPixelStart;
  156.  
  157. // Calculate final average luminance
  158. finalAvgLuminance = tempTotalContribution / float(diff);
  159. }
  160. else
  161. {
  162. // Pass current contribution further and increase lumaValue
  163. finalAvgLuminance = tempTotalContribution;
  164. lumaValue++;
  165. }
  166. }
  167.  
  168. // Save average luminance
  169. g_avgLuminance[uint2(0,0)] = finalAvgLuminance;
  170. }
  171. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement