blob: c2d56a19e3667eb629e19c7f81db125d21a6a039 [file] [log] [blame]
/*
* Copyright 2020 Google LLC
*
*/
/*
* Copyright (c) 2020, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
* was not distributed with this source code in the LICENSE file, you can
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
* Media Patent License 1.0 was not distributed with this source code in the
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
#include "ps_cbuf.h"
#define kDefaultWhiteLevelSRGB 100.0f // sRGB
#define kDefaultWhiteLevelPQ \
10000.0f // PQ https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.2100-0-201607-I!!PDF-E.pdf
#define kDefaultWhiteLevelHLG \
1000.0 // HLG https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.2100-0-201607-I!!PDF-E.pdf
// color conversion matrixs. It works with liner colors
static const float3x3 BT709_TO_BT2020 = { // ref: ARIB STD-B62 and BT.2087
0.6274, 0.3293, 0.0433, 0.0691, 0.9195, 0.0114, 0.0164, 0.0880, 0.8956};
static const float3x3 BT2020_TO_BT709 = {1.6605, -0.5877, -0.0728, -0.1246, 1.1330, -0.0084, -0.0182, -0.1006, 1.1187};
// YUV to RGB matrixs:
// BT.709
static const float3x3 YCbCR_TO_SRGB = {1.1644f, 0.0f, 1.7927f, 1.1644f, -0.2133f, -0.5329f, 1.1644f, 2.1124f, 0.0f};
// BT.2020
static const float3x3 YCbCr_TO_BT2020 = {1.163746465f, -0.028815145f, 2.823537589f, 1.164383561f, -0.258509894f,
0.379693635f, 1.164383561f, 2.385315708f, 0.021554502f};
float3 SRGB_OETF(float3 L) {
const float thr = 1.0;
L = L / kDefaultWhiteLevelSRGB;
float3 dark = L * 12.92;
float3 light = 1.055 * (float3)pow(abs(L), 1.0 / 2.4) - 0.055;
float3 r;
bool3 cri = L <= 0.0031308;
r = cri ? dark : light;
//#define SHOW_COLOR
#ifdef SHOW_COLOR
float Y = 0.2126f * r.x + 0.7152f * r.y + 0.0722f * r.z;
float3 ret = r;
float gray = (3.0 - Y) / 4.0;
float3 gray3 = float3(gray, gray, gray);
if (Y > 3.0) {
ret = float3(1.0, 0.0, 0.0);
} else if (gray < 0.5) {
ret = gray3;
}
return ret;
#else
return r;
#endif
}
float3 SRGB_EOTF(float3 E) {
float3 dark = E / 12.92;
float3 light = pow(abs((E + 0.055) / (1 + 0.055)), 2.4);
bool3 cri = E.xyz <= 0.04045;
float3 r = cri ? dark : light;
r = r * kDefaultWhiteLevelSRGB;
return r;
}
float3 BT709_EOTF(float3 rgb) {
const float a = 1.09929682f;
const float b = 0.0180539685f;
const float threshold = 0.081242864f; // fromLiner(BT709, 0.0180539685f)
bool3 cri = rgb < threshold;
float3 dark = rgb / 4.5f;
float3 light = pow(abs((rgb + a - 1.0f) / a), 1.0f / 0.45f);
float3 liner709 = cri ? dark : light;
return liner709 * kDefaultWhiteLevelSRGB;
}
// input: normalized L in units of RefWhite (1.0=100nits), output: normalized E
float3 PQ_OETF(float3 L) {
const float c1 = 0.8359375; // 3424.f/4096.f;
const float c2 = 18.8515625; // 2413.f/4096.f*32.f;
const float c3 = 18.6875; // 2392.f/4096.f*32.f;
const float m1 = 0.159301758125; // 2610.f / 4096.f / 4;
const float m2 = 78.84375; // 2523.f / 4096.f * 128.f;
L = L / kDefaultWhiteLevelPQ; // normalize liner color
float3 Lm1 = pow(abs(L), m1);
float3 X = (c1 + c2 * Lm1) / (1 + c3 * Lm1);
float3 res = pow(abs(X), m2);
return res;
}
// input: normalized E (0.0, 1.0), output: normalized L in units of RefWhite
float3 PQ_EOTF(float3 E) {
const float c1 = 0.8359375; // 3424.f/4096.f;
const float c2 = 18.8515625; // 2413.f/4096.f*32.f;
const float c3 = 18.6875; // 2392.f/4096.f*32.f;
const float m1 = 0.159301758125; // 2610.f / 4096.f / 4;
const float m2 = 78.84375; // 2523.f / 4096.f * 128.f;
float3 M = c2 - c3 * pow(abs(E), 1 / m2);
float3 N = max(pow(abs(E), 1 / m2) - c1, 0);
float3 L = pow(abs(N / M), 1 / m1); // normalized nits (1.0 = 10000nits)
L = L * kDefaultWhiteLevelPQ; // white level in range (0 - kDefaultWhiteLevelPQ);
return L;
}
float3 ARIB_STD_B67_EOTF(float3 E) {
const float a = 0.17883277f;
const float b = 0.28466892f;
const float c = 0.55991073f;
const float Lmax = 12.0f;
float3 dark = (E * 2.0f) * (E * 2.0f);
float3 light = exp((E - c) / a) + b;
bool3 cri = E <= 0.5f;
float3 r = cri ? dark : light;
return r / Lmax * kDefaultWhiteLevelHLG;
}
struct PSInput {
float4 position : SV_POSITION;
float2 uv : TEXCOORD;
};
Texture2D g_textureY : register(t0);
Texture2D g_textureU : register(t1);
Texture2D g_textureV : register(t2);
SamplerState g_samplerY : register(s0);
SamplerState g_samplerUV : register(s1);
float4 main(PSInput fragment) : SV_TARGET {
float3 ycbcr;
if (hdr_10_10_10_2) {
uint2 DTid, ptex_dim, ptex_ind, ptex_ind_temp;
float2 ptex_pos, tex_pos, mag_ratio;
mag_ratio.x = float(disp_w) / float(frame_w);
mag_ratio.y = float(disp_h) / float(frame_h);
DTid.x = uint(floor(fragment.uv.x * disp_w));
DTid.y = uint(floor(fragment.uv.y * disp_h));
tex_pos = (float2(DTid) + 0.5f) / mag_ratio;
ptex_dim = uint2(ptex_w, ptex_h);
ptex_ind = uint2(floor(tex_pos.x / 3), floor(tex_pos.y));
ptex_pos.x = ((float)ptex_ind + 0.5f) / (float)(ptex_dim.x);
ptex_pos.y = tex_pos.y / (float)(ptex_dim.y);
ycbcr.x = g_textureY.Sample(g_samplerY, ptex_pos)[uint(floor(tex_pos.x)) % 3];
ptex_dim >>= 1;
DTid >>= 1;
ptex_ind_temp = uint2(floor((float(DTid.x + 0.5f) / mag_ratio.x) / 3), floor(float(DTid.y + 0.5f) / mag_ratio.y));
ptex_ind = ptex_ind_temp; // >> 1;
ptex_pos = ((float2)ptex_ind + 0.5f) / (float2)(ptex_dim);
ycbcr.y = g_textureU.Sample(g_samplerUV, ptex_pos)[uint(floor(float(DTid.x + 0.5f) / mag_ratio.x)) % 3];
ycbcr.z = g_textureV.Sample(g_samplerUV, ptex_pos)[uint(floor(float(DTid.x + 0.5f) / mag_ratio.x)) % 3];
} else if (isMonochrome) {
float2 cbcr = isMonochrome ? float2(0.5, 0.5)
: float2(g_textureU.Sample(g_samplerUV, fragment.uv).x,
g_textureV.Sample(g_samplerUV, fragment.uv).x);
ycbcr = float3(g_textureY.Sample(g_samplerY, fragment.uv).x, cbcr);
} else {
ycbcr = float3(g_textureY.Sample(g_samplerY, fragment.uv).x, g_textureU.Sample(g_samplerUV, fragment.uv).x,
g_textureV.Sample(g_samplerUV, fragment.uv).x);
}
ycbcr *= scale_factor;
ycbcr -= float3(0.0625, 0.5, 0.5);
float4 result = float4(mul(YCbCR_TO_SRGB, ycbcr), 1.0f);
return result;
}