mirror of
				https://github.com/gnif/LookingGlass.git
				synced 2025-11-04 06:31:54 +00:00 
			
		
		
		
	[client] egl: make it possible to configure HDR to SDR mapping
This commit is contained in:
		@@ -51,6 +51,8 @@ struct DesktopShader
 | 
			
		||||
  GLint uNVGain;
 | 
			
		||||
  GLint uCBMode;
 | 
			
		||||
  GLint uIsHDR;
 | 
			
		||||
  GLint uMapHDRtoSDR;
 | 
			
		||||
  GLint uMapHDRGain;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct EGL_Desktop
 | 
			
		||||
@@ -85,6 +87,11 @@ struct EGL_Desktop
 | 
			
		||||
  bool useDMA;
 | 
			
		||||
  LG_RendererFormat format;
 | 
			
		||||
 | 
			
		||||
  // map HDR content to SDR
 | 
			
		||||
  bool  mapHDRtoSDR;
 | 
			
		||||
  int   peakLuminance;
 | 
			
		||||
  int   maxCLL;
 | 
			
		||||
 | 
			
		||||
  EGL_PostProcess * pp;
 | 
			
		||||
  _Atomic(bool) processFrame;
 | 
			
		||||
};
 | 
			
		||||
@@ -110,12 +117,14 @@ static bool egl_initDesktopShader(
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  shader->uTransform   = egl_shaderGetUniform(shader->shader, "transform"  );
 | 
			
		||||
  shader->uDesktopSize = egl_shaderGetUniform(shader->shader, "desktopSize");
 | 
			
		||||
  shader->uScaleAlgo   = egl_shaderGetUniform(shader->shader, "scaleAlgo"  );
 | 
			
		||||
  shader->uNVGain      = egl_shaderGetUniform(shader->shader, "nvGain"     );
 | 
			
		||||
  shader->uCBMode      = egl_shaderGetUniform(shader->shader, "cbMode"     );
 | 
			
		||||
  shader->uIsHDR       = egl_shaderGetUniform(shader->shader, "isHDR"      );
 | 
			
		||||
  shader->uTransform    = egl_shaderGetUniform(shader->shader, "transform"   );
 | 
			
		||||
  shader->uDesktopSize  = egl_shaderGetUniform(shader->shader, "desktopSize" );
 | 
			
		||||
  shader->uScaleAlgo    = egl_shaderGetUniform(shader->shader, "scaleAlgo"   );
 | 
			
		||||
  shader->uNVGain       = egl_shaderGetUniform(shader->shader, "nvGain"      );
 | 
			
		||||
  shader->uCBMode       = egl_shaderGetUniform(shader->shader, "cbMode"      );
 | 
			
		||||
  shader->uIsHDR        = egl_shaderGetUniform(shader->shader, "isHDR"       );
 | 
			
		||||
  shader->uMapHDRtoSDR  = egl_shaderGetUniform(shader->shader, "mapHDRtoSDR" );
 | 
			
		||||
  shader->uMapHDRGain   = egl_shaderGetUniform(shader->shader, "mapHDRGain"  );
 | 
			
		||||
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
@@ -184,6 +193,10 @@ bool egl_desktopInit(EGL * egl, EGL_Desktop ** desktop_, EGLDisplay * display,
 | 
			
		||||
  desktop->scaleAlgo = option_get_int("egl", "scale"    );
 | 
			
		||||
  desktop->useDMA    = useDMA;
 | 
			
		||||
 | 
			
		||||
  desktop->mapHDRtoSDR   = option_get_bool("egl", "mapHDRtoSDR"  );
 | 
			
		||||
  desktop->peakLuminance = option_get_int ("egl", "peakLuminance");
 | 
			
		||||
  desktop->maxCLL        = option_get_int ("egl", "maxCLL"       );
 | 
			
		||||
 | 
			
		||||
  if (!egl_postProcessInit(&desktop->pp))
 | 
			
		||||
  {
 | 
			
		||||
    DEBUG_ERROR("Failed to initialize the post process manager");
 | 
			
		||||
@@ -274,6 +287,14 @@ void egl_desktopConfigUI(EGL_Desktop * desktop)
 | 
			
		||||
  }
 | 
			
		||||
  igSliderInt("##nvgain", &desktop->nvGain, 0, desktop->nvMax, format, 0);
 | 
			
		||||
  igPopItemWidth();
 | 
			
		||||
 | 
			
		||||
  igSeparator();
 | 
			
		||||
  igCheckbox("Map HDR content to SDR", &desktop->mapHDRtoSDR);
 | 
			
		||||
  igSliderInt("Peak Luminance", &desktop->peakLuminance, 1, 10000,
 | 
			
		||||
      "%d nits",
 | 
			
		||||
      ImGuiInputTextFlags_CharsDecimal);
 | 
			
		||||
  igSliderInt("Max content light level (nits)", &desktop->maxCLL, 1, 10000,
 | 
			
		||||
      "%d nits", ImGuiInputTextFlags_CharsDecimal);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool egl_desktopSetup(EGL_Desktop * desktop, const LG_RendererFormat format)
 | 
			
		||||
@@ -458,6 +479,9 @@ bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth,
 | 
			
		||||
    desktop->useDMA && texture == desktop->texture ?
 | 
			
		||||
      &desktop->dmaShader : &desktop->shader;
 | 
			
		||||
 | 
			
		||||
  const float mapHDRGain =
 | 
			
		||||
    desktop->maxCLL / desktop->peakLuminance;
 | 
			
		||||
 | 
			
		||||
  EGL_Uniform uniforms[] =
 | 
			
		||||
  {
 | 
			
		||||
    {
 | 
			
		||||
@@ -490,6 +514,16 @@ bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth,
 | 
			
		||||
      .type        = EGL_UNIFORM_TYPE_1I,
 | 
			
		||||
      .location    = shader->uIsHDR,
 | 
			
		||||
      .i           = { desktop->hdr }
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      .type        = EGL_UNIFORM_TYPE_1I,
 | 
			
		||||
      .location    = shader->uMapHDRtoSDR,
 | 
			
		||||
      .i           = { desktop->mapHDRtoSDR }
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      .type        = EGL_UNIFORM_TYPE_1F,
 | 
			
		||||
      .location    = shader->uMapHDRGain,
 | 
			
		||||
      .f           = { mapHDRGain }
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -202,6 +202,27 @@ static struct Option egl_options[] =
 | 
			
		||||
    .type         = OPTION_TYPE_BOOL,
 | 
			
		||||
    .value.x_bool = true
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    .module       = "egl",
 | 
			
		||||
    .name         = "mapHDRtoSDR",
 | 
			
		||||
    .description  = "Map HDR content to the SDR color space",
 | 
			
		||||
    .type         = OPTION_TYPE_BOOL,
 | 
			
		||||
    .value.x_bool = true
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    .module       = "egl",
 | 
			
		||||
    .name         = "peakLuminance",
 | 
			
		||||
    .description  = "The peak luminance level in nits for HDR to SDR mapping",
 | 
			
		||||
    .type         = OPTION_TYPE_INT,
 | 
			
		||||
    .value.x_int  = 250,
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    .module       = "egl",
 | 
			
		||||
    .name         = "maxCLL",
 | 
			
		||||
    .description  = "Maximum content light level in nits for HDR to SDR mapping",
 | 
			
		||||
    .type         = OPTION_TYPE_INT,
 | 
			
		||||
    .value.x_int  = 10000,
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  {0}
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -21,6 +21,8 @@ uniform int   scaleAlgo;
 | 
			
		||||
uniform float nvGain;
 | 
			
		||||
uniform int   cbMode;
 | 
			
		||||
uniform bool  isHDR;
 | 
			
		||||
uniform bool  mapHDRtoSDR;
 | 
			
		||||
uniform float mapHDRGain;
 | 
			
		||||
 | 
			
		||||
void main()
 | 
			
		||||
{
 | 
			
		||||
@@ -40,8 +42,8 @@ void main()
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (isHDR)
 | 
			
		||||
    color.rgb = mapToSDR(color.rgb);
 | 
			
		||||
  if (isHDR && mapHDRtoSDR)
 | 
			
		||||
    color.rgb = mapToSDR(color.rgb, mapHDRGain);
 | 
			
		||||
 | 
			
		||||
  if (cbMode > 0)
 | 
			
		||||
    color = cbTransform(color, cbMode);
 | 
			
		||||
 
 | 
			
		||||
@@ -13,14 +13,11 @@
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
// Configuration ---------------------------------------------------------------
 | 
			
		||||
const float peakLuminance = 250.0;   // Peak playback screen luminance in nits
 | 
			
		||||
const float knee          = 0.75;    // Compressor knee position
 | 
			
		||||
const float ratio         = 4.0;     // Compressor ratio: 1 = disabled, <1 = expander
 | 
			
		||||
const float maxCLL        = 10000.0; // Maximum content light level in nits
 | 
			
		||||
// -----------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
// Precalculated values
 | 
			
		||||
const float gain       = maxCLL / peakLuminance;
 | 
			
		||||
const float compressor = 1.0 / ratio;
 | 
			
		||||
 | 
			
		||||
// PQ constants
 | 
			
		||||
@@ -43,10 +40,11 @@ float midGain(vec3 pixel)
 | 
			
		||||
      min(pixel.r, pixel.g)); // min = b
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vec3 compress(vec3 pixel)
 | 
			
		||||
vec3 compress(vec3 pixel, float gain)
 | 
			
		||||
{
 | 
			
		||||
  float gain = maxGain(pixel);
 | 
			
		||||
  return pixel * (gain < knee ? gain : knee + max(gain - knee, 0.0) * compressor) / gain;
 | 
			
		||||
  float maxGain = maxGain(pixel);
 | 
			
		||||
  return pixel * (maxGain < knee ? maxGain :
 | 
			
		||||
      knee + max(maxGain - knee, 0.0) * compressor) / maxGain;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vec3 fixClip(vec3 pixel)
 | 
			
		||||
@@ -67,7 +65,7 @@ vec3 fixClip(vec3 pixel)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns luminance in nits
 | 
			
		||||
vec3 pq2lin(vec3 pq)
 | 
			
		||||
vec3 pq2lin(vec3 pq, float gain)
 | 
			
		||||
{
 | 
			
		||||
  vec3 p = pow(pq, vec3(m2inv));
 | 
			
		||||
  vec3 d = max(p - c1, vec3(0.0)) / (c2 - c3 * p);
 | 
			
		||||
@@ -101,8 +99,8 @@ vec3 bt2020to709(vec3 bt2020)
 | 
			
		||||
    bt2020.r * -0.0182 + bt2020.g * -0.1006 + bt2020.b * 1.1187);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vec3 mapToSDR(vec3 color)
 | 
			
		||||
vec3 mapToSDR(vec3 color, float gain)
 | 
			
		||||
{
 | 
			
		||||
  vec3 lin = bt2020to709(pq2lin(color.rgb));
 | 
			
		||||
  return lin2srgb(compress(lin));
 | 
			
		||||
  vec3 lin = bt2020to709(pq2lin(color.rgb, gain));
 | 
			
		||||
  return lin2srgb(compress(lin, gain));
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user