Add support for DXGI_FORMAT_R9G9B9E5_SHAREDEXP
Fixes RE9 and probably other games with HDR outputs Signed-off-by: Etienne JUVIGNY <[email protected]>
This commit is contained in:
1 parent
8ce8618181
commit
30af9bde35
1 file changed
+75
-2
@@ -853,7 +853,8 @@ static bool supported_input(Plane plane, DXGI_FORMAT format)
|
|||||||
format == DXGI_FORMAT_R10G10B10A2_UNORM || format == DXGI_FORMAT_R10G10B10A2_TYPELESS ||
|
format == DXGI_FORMAT_R10G10B10A2_UNORM || format == DXGI_FORMAT_R10G10B10A2_TYPELESS ||
|
||||||
format == DXGI_FORMAT_R8G8B8A8_UNORM || format == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB ||
|
format == DXGI_FORMAT_R8G8B8A8_UNORM || format == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB ||
|
||||||
format == DXGI_FORMAT_R8G8B8A8_TYPELESS || format == DXGI_FORMAT_B8G8R8A8_UNORM ||
|
format == DXGI_FORMAT_R8G8B8A8_TYPELESS || format == DXGI_FORMAT_B8G8R8A8_UNORM ||
|
||||||
format == DXGI_FORMAT_B8G8R8A8_UNORM_SRGB || format == DXGI_FORMAT_B8G8R8A8_TYPELESS;
|
format == DXGI_FORMAT_B8G8R8A8_UNORM_SRGB || format == DXGI_FORMAT_B8G8R8A8_TYPELESS ||
|
||||||
|
format == DXGI_FORMAT_R9G9B9E5_SHAREDEXP;
|
||||||
case Plane::Depth:
|
case Plane::Depth:
|
||||||
return format == DXGI_FORMAT_D32_FLOAT || format == DXGI_FORMAT_R32_FLOAT ||
|
return format == DXGI_FORMAT_D32_FLOAT || format == DXGI_FORMAT_R32_FLOAT ||
|
||||||
format == DXGI_FORMAT_R32_TYPELESS || format == DXGI_FORMAT_D32_FLOAT_S8X24_UINT ||
|
format == DXGI_FORMAT_R32_TYPELESS || format == DXGI_FORMAT_D32_FLOAT_S8X24_UINT ||
|
||||||
@@ -880,7 +881,8 @@ static bool supported_output(DXGI_FORMAT format)
|
|||||||
format == DXGI_FORMAT_R32G32B32A32_FLOAT || format == DXGI_FORMAT_R11G11B10_FLOAT ||
|
format == DXGI_FORMAT_R32G32B32A32_FLOAT || format == DXGI_FORMAT_R11G11B10_FLOAT ||
|
||||||
format == DXGI_FORMAT_R10G10B10A2_UNORM || format == DXGI_FORMAT_R10G10B10A2_TYPELESS ||
|
format == DXGI_FORMAT_R10G10B10A2_UNORM || format == DXGI_FORMAT_R10G10B10A2_TYPELESS ||
|
||||||
format == DXGI_FORMAT_R8G8B8A8_UNORM || format == DXGI_FORMAT_R8G8B8A8_TYPELESS ||
|
format == DXGI_FORMAT_R8G8B8A8_UNORM || format == DXGI_FORMAT_R8G8B8A8_TYPELESS ||
|
||||||
format == DXGI_FORMAT_B8G8R8A8_UNORM || format == DXGI_FORMAT_B8G8R8A8_TYPELESS;
|
format == DXGI_FORMAT_B8G8R8A8_UNORM || format == DXGI_FORMAT_B8G8R8A8_TYPELESS ||
|
||||||
|
format == DXGI_FORMAT_R9G9B9E5_SHAREDEXP;
|
||||||
}
|
}
|
||||||
|
|
||||||
static float unorm(uint32_t value, int bits)
|
static float unorm(uint32_t value, int bits)
|
||||||
@@ -943,6 +945,20 @@ static void convert_row_in(Plane plane, DXGI_FORMAT format, const uint8_t* sourc
|
|||||||
rgba[2] = unorm(source[x * 4 + 0], 8);
|
rgba[2] = unorm(source[x * 4 + 0], 8);
|
||||||
rgba[3] = unorm(source[x * 4 + 3], 8);
|
rgba[3] = unorm(source[x * 4 + 3], 8);
|
||||||
break;
|
break;
|
||||||
|
case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:
|
||||||
|
{
|
||||||
|
// Microsoft spec: c = (p >> offset) & 0x1FF, E = (p >> 27) & 0x1F,
|
||||||
|
// v = c * 2^(E - 24). E == 0 means an exact zero.
|
||||||
|
uint32_t packed;
|
||||||
|
std::memcpy(&packed, source + x * 4, 4);
|
||||||
|
uint32_t e = (packed >> 27) & 0x1Fu;
|
||||||
|
float scale = (e == 0) ? 0.0f : std::ldexp(1.0f, (int)e - 24);
|
||||||
|
rgba[0] = static_cast<float>((packed >> 0) & 0x1FFu) * scale;
|
||||||
|
rgba[1] = static_cast<float>((packed >> 9) & 0x1FFu) * scale;
|
||||||
|
rgba[2] = static_cast<float>((packed >> 18) & 0x1FFu) * scale;
|
||||||
|
rgba[3] = 1.0f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: // RGBA8 variants
|
default: // RGBA8 variants
|
||||||
for (int c = 0; c < 4; ++c)
|
for (int c = 0; c < 4; ++c)
|
||||||
rgba[c] = unorm(source[x * 4 + c], 8);
|
rgba[c] = unorm(source[x * 4 + c], 8);
|
||||||
@@ -1073,6 +1089,56 @@ static void convert_r11g11b10_row(const uint8_t* source, uint16_t* half, UINT wi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Packs one RGBA16F DLSS texel into the 9-9-9-5 shared-exponent layout.
|
||||||
|
// Microsoft spec: v = c * 2^(E - 24), c in [0, 511]. The exponent is chosen as
|
||||||
|
// the smallest E such that all channels fit in 9 bits, then each channel is
|
||||||
|
// rounded to the nearest representable value (round-half-even, matching
|
||||||
|
// D3D's conversion semantics). Values above the format's max (65024.0) are
|
||||||
|
// clamped, like D3D12 does.
|
||||||
|
static void rgbe_pack(const float rgba[4], uint8_t* destination)
|
||||||
|
{
|
||||||
|
const float MAX_VALUE = 65024.0f; // 511 * 2^(24 - 24)
|
||||||
|
float r = rgba[0] < 0.0f ? 0.0f : (rgba[0] > MAX_VALUE ? MAX_VALUE : rgba[0]);
|
||||||
|
float g = rgba[1] < 0.0f ? 0.0f : (rgba[1] > MAX_VALUE ? MAX_VALUE : rgba[1]);
|
||||||
|
float b = rgba[2] < 0.0f ? 0.0f : (rgba[2] > MAX_VALUE ? MAX_VALUE : rgba[2]);
|
||||||
|
|
||||||
|
float mx = fmaxf(fmaxf(r, g), b);
|
||||||
|
int e;
|
||||||
|
if (mx == 0.0f)
|
||||||
|
{
|
||||||
|
e = 0; // exponent 0 encodes an exact zero in this format
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Smallest scale (i.e. smallest e) such that mx / scale <= 511. This
|
||||||
|
// puts the largest channel in the normalized 9-bit range [256, 511],
|
||||||
|
// which gives every channel the maximum precision the format allows.
|
||||||
|
e = 31;
|
||||||
|
for (int et = 1; et <= 31; ++et)
|
||||||
|
{
|
||||||
|
if (mx / std::ldexp(1.0f, et - 24) <= 511.0f) { e = et; break; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const float scale = std::ldexp(1.0f, e - 24);
|
||||||
|
const float inv = 1.0f / scale;
|
||||||
|
|
||||||
|
// Round to nearest, ties to even (D3D round-to-nearest-even semantics).
|
||||||
|
auto to_c = [](float v, float inv) -> uint32_t
|
||||||
|
{
|
||||||
|
double d = std::nearbyint(v * inv); // round-half-even
|
||||||
|
if (d < 0.0) d = 0.0;
|
||||||
|
if (d > 511.0) d = 511.0;
|
||||||
|
return static_cast<uint32_t>(d);
|
||||||
|
};
|
||||||
|
|
||||||
|
uint32_t packed = 0;
|
||||||
|
packed |= to_c(r, inv) << 0;
|
||||||
|
packed |= to_c(g, inv) << 9;
|
||||||
|
packed |= to_c(b, inv) << 18;
|
||||||
|
packed |= (e & 0x1Fu) << 27;
|
||||||
|
std::memcpy(destination, &packed, 4);
|
||||||
|
}
|
||||||
|
|
||||||
// Converts one row of RGBA16F DLSS output into the game's output format.
|
// Converts one row of RGBA16F DLSS output into the game's output format.
|
||||||
static void convert_row_out(DXGI_FORMAT format, const uint16_t* source, uint8_t* destination, UINT width)
|
static void convert_row_out(DXGI_FORMAT format, const uint16_t* source, uint8_t* destination, UINT width)
|
||||||
{
|
{
|
||||||
@@ -1117,6 +1183,12 @@ static void convert_row_out(DXGI_FORMAT format, const uint16_t* source, uint8_t*
|
|||||||
destination[x * 4 + 2] = static_cast<uint8_t>(to_unorm(half_to_float(texel[0]), 8));
|
destination[x * 4 + 2] = static_cast<uint8_t>(to_unorm(half_to_float(texel[0]), 8));
|
||||||
destination[x * 4 + 3] = static_cast<uint8_t>(to_unorm(half_to_float(texel[3]), 8));
|
destination[x * 4 + 3] = static_cast<uint8_t>(to_unorm(half_to_float(texel[3]), 8));
|
||||||
break;
|
break;
|
||||||
|
case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:
|
||||||
|
{
|
||||||
|
float rgba[4] = {half_to_float(texel[0]), half_to_float(texel[1]), half_to_float(texel[2]), 1.0f};
|
||||||
|
rgbe_pack(rgba, destination + x * 4);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: // RGBA8
|
default: // RGBA8
|
||||||
for (int c = 0; c < 4; ++c)
|
for (int c = 0; c < 4; ++c)
|
||||||
destination[x * 4 + c] = static_cast<uint8_t>(to_unorm(half_to_float(texel[c]), 8));
|
destination[x * 4 + c] = static_cast<uint8_t>(to_unorm(half_to_float(texel[c]), 8));
|
||||||
@@ -2410,6 +2482,7 @@ static bool vram_color_blit_supported(VkFormat format, bool output)
|
|||||||
case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
|
case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
|
||||||
case VK_FORMAT_R8G8B8A8_UNORM:
|
case VK_FORMAT_R8G8B8A8_UNORM:
|
||||||
case VK_FORMAT_B8G8R8A8_UNORM:
|
case VK_FORMAT_B8G8R8A8_UNORM:
|
||||||
|
case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
Reference in new issue
Block a user