[GPU] Select alpha for A8 resolves
Treat k_8 + LOW_BLUE as alpha selection. 5451080D uses this to resolve its opacity plane, and 4D530808 does the same for a fog lighting pass. Their blue channels are black, so treating LOW_BLUE as an R/B exchange drops data. Informed by XGCopySurface decompilation, which combines source and inverse dest swizzle, plus notcing how L8 and A8 share the same texture format.
This commit is contained in:
committed by
Radosław Gliński
parent
b98037bed2
commit
2b3f0cb456
@@ -340,47 +340,88 @@ uint XeResolveEdramPixelStrideBytes(XeResolveInfo resolve_info) {
|
||||
}
|
||||
}
|
||||
|
||||
void XeResolveUnpack32bpp8RedSamples(
|
||||
uint4_xe packed_0123, uint4_xe packed_4567, uint format, bool swap,
|
||||
// L8 and A8 both use GPUTEXTUREFORMAT_8, which is confirmed by
|
||||
// XGCopySurface decompilation, the software version of the copy. It combines
|
||||
// the source swizzle with the inverse dest swizzle. Resolve maps L8 ORRR
|
||||
// swizzle to LOW_RED and A8 RZZZ swizzle to LOW_BLUE, routing red or alpha
|
||||
// respectively to the stored component. So, this is source selection for
|
||||
// k_8 dests, not a byte change.
|
||||
//
|
||||
// 5451080D resolves an opacity plane it composites the frame through from
|
||||
// the alpha of an 8_8_8_8_GAMMA target via k_8 + LOW_BLUE. 4D530808 does the
|
||||
// same for a fog lighting pass. The blue of those targets are black, and
|
||||
// literally interpreting the swap results in missing composites and lighting.
|
||||
void XeResolveUnpack32bpp8ScalarSamples(
|
||||
uint4_xe packed_0123, uint4_xe packed_4567, uint format,
|
||||
bool source_blue, bool source_alpha,
|
||||
out_param_xe(float4_xe, samples_0123),
|
||||
out_param_xe(float4_xe, samples_4567)) {
|
||||
switch (format) {
|
||||
case kXenosColorRenderTargetFormat_8_8_8_8:
|
||||
case kXenosColorRenderTargetFormat_8_8_8_8_GAMMA: {
|
||||
uint shift = swap ? 16u : 0u;
|
||||
uint shift = source_alpha ? 24u : (source_blue ? 16u : 0u);
|
||||
samples_0123 = XeUnpackR8UNormX4(packed_0123 >> shift);
|
||||
samples_4567 = XeUnpackR8UNormX4(packed_4567 >> shift);
|
||||
} break;
|
||||
case kXenosColorRenderTargetFormat_2_10_10_10:
|
||||
case kXenosColorRenderTargetFormat_2_10_10_10_AS_10_10_10_10: {
|
||||
uint shift = swap ? 20u : 0u;
|
||||
samples_0123 = XeUnpackR10UNormX4(packed_0123 >> shift);
|
||||
samples_4567 = XeUnpackR10UNormX4(packed_4567 >> shift);
|
||||
} break;
|
||||
case kXenosColorRenderTargetFormat_2_10_10_10_AS_10_10_10_10:
|
||||
dont_flatten_xe if (source_alpha) {
|
||||
// 2 bit unsigned repeating fraction alpha.
|
||||
samples_0123 = float4_xe(packed_0123 >> 30u) * (1.0f / 3.0f);
|
||||
samples_4567 = float4_xe(packed_4567 >> 30u) * (1.0f / 3.0f);
|
||||
} else {
|
||||
uint shift = source_blue ? 20u : 0u;
|
||||
samples_0123 = XeUnpackR10UNormX4(packed_0123 >> shift);
|
||||
samples_4567 = XeUnpackR10UNormX4(packed_4567 >> shift);
|
||||
}
|
||||
break;
|
||||
case kXenosColorRenderTargetFormat_2_10_10_10_FLOAT:
|
||||
case kXenosColorRenderTargetFormat_2_10_10_10_FLOAT_AS_16_16_16_16: {
|
||||
uint shift = swap ? 20u : 0u;
|
||||
samples_0123 = XeUnpackR10FloatX4(packed_0123 >> shift);
|
||||
samples_4567 = XeUnpackR10FloatX4(packed_4567 >> shift);
|
||||
} break;
|
||||
case kXenosColorRenderTargetFormat_2_10_10_10_FLOAT_AS_16_16_16_16:
|
||||
dont_flatten_xe if (source_alpha) {
|
||||
// The alpha is a 2 bit unsigned repeating fraction as well, only
|
||||
// RGB are 7e3 floats.
|
||||
samples_0123 = float4_xe(packed_0123 >> 30u) * (1.0f / 3.0f);
|
||||
samples_4567 = float4_xe(packed_4567 >> 30u) * (1.0f / 3.0f);
|
||||
} else {
|
||||
uint shift = source_blue ? 20u : 0u;
|
||||
samples_0123 = XeUnpackR10FloatX4(packed_0123 >> shift);
|
||||
samples_4567 = XeUnpackR10FloatX4(packed_4567 >> shift);
|
||||
}
|
||||
break;
|
||||
case kXenosColorRenderTargetFormat_16_16:
|
||||
samples_0123 = XeUnpackR16EdramX4(packed_0123);
|
||||
samples_4567 = XeUnpackR16EdramX4(packed_4567);
|
||||
dont_flatten_xe if (source_alpha) {
|
||||
// Missing alpha is 1.0 before MSAA averaging and exponent bias.
|
||||
samples_0123 = float_x4_xe(1.0f);
|
||||
samples_4567 = float_x4_xe(1.0f);
|
||||
} else {
|
||||
samples_0123 = XeUnpackR16EdramX4(packed_0123);
|
||||
samples_4567 = XeUnpackR16EdramX4(packed_4567);
|
||||
}
|
||||
break;
|
||||
case kXenosColorRenderTargetFormat_16_16_FLOAT:
|
||||
samples_0123.x = unpack_half_2x16_xe(packed_0123.x).x;
|
||||
samples_0123.y = unpack_half_2x16_xe(packed_0123.y).x;
|
||||
samples_0123.z = unpack_half_2x16_xe(packed_0123.z).x;
|
||||
samples_0123.w = unpack_half_2x16_xe(packed_0123.w).x;
|
||||
samples_4567.x = unpack_half_2x16_xe(packed_4567.x).x;
|
||||
samples_4567.y = unpack_half_2x16_xe(packed_4567.y).x;
|
||||
samples_4567.z = unpack_half_2x16_xe(packed_4567.z).x;
|
||||
samples_4567.w = unpack_half_2x16_xe(packed_4567.w).x;
|
||||
dont_flatten_xe if (source_alpha) {
|
||||
samples_0123 = float_x4_xe(1.0f);
|
||||
samples_4567 = float_x4_xe(1.0f);
|
||||
} else {
|
||||
samples_0123.x = unpack_half_2x16_xe(packed_0123.x).x;
|
||||
samples_0123.y = unpack_half_2x16_xe(packed_0123.y).x;
|
||||
samples_0123.z = unpack_half_2x16_xe(packed_0123.z).x;
|
||||
samples_0123.w = unpack_half_2x16_xe(packed_0123.w).x;
|
||||
samples_4567.x = unpack_half_2x16_xe(packed_4567.x).x;
|
||||
samples_4567.y = unpack_half_2x16_xe(packed_4567.y).x;
|
||||
samples_4567.z = unpack_half_2x16_xe(packed_4567.z).x;
|
||||
samples_4567.w = unpack_half_2x16_xe(packed_4567.w).x;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Treat as 32_FLOAT.
|
||||
samples_0123 = uint_bits_to_float_xe(packed_0123);
|
||||
samples_4567 = uint_bits_to_float_xe(packed_4567);
|
||||
dont_flatten_xe if (source_alpha) {
|
||||
samples_0123 = float_x4_xe(1.0f);
|
||||
samples_4567 = float_x4_xe(1.0f);
|
||||
} else {
|
||||
samples_0123 = uint_bits_to_float_xe(packed_0123);
|
||||
samples_4567 = uint_bits_to_float_xe(packed_4567);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -438,29 +479,49 @@ uint XeResolveEdramPixelStrideBytes(XeResolveInfo resolve_info) {
|
||||
}
|
||||
}
|
||||
|
||||
void XeResolveUnpack64bpp8RedUnswappedSamples(
|
||||
// The caller selects the second dword for blue or alpha. Alpha occupies the
|
||||
// high half in 16 bit component formats.
|
||||
void XeResolveUnpack64bpp8ScalarSamples(
|
||||
uint4_xe packed_0123, uint4_xe packed_4567, uint format,
|
||||
out_param_xe(float4_xe, samples_0123),
|
||||
bool source_alpha, out_param_xe(float4_xe, samples_0123),
|
||||
out_param_xe(float4_xe, samples_4567)) {
|
||||
switch (format) {
|
||||
case kXenosColorRenderTargetFormat_16_16_16_16:
|
||||
samples_0123 = XeUnpackR16EdramX4(packed_0123);
|
||||
samples_4567 = XeUnpackR16EdramX4(packed_4567);
|
||||
break;
|
||||
case kXenosColorRenderTargetFormat_16_16_16_16: {
|
||||
uint shift = source_alpha ? 16u : 0u;
|
||||
samples_0123 = XeUnpackR16EdramX4(packed_0123 >> shift);
|
||||
samples_4567 = XeUnpackR16EdramX4(packed_4567 >> shift);
|
||||
} break;
|
||||
case kXenosColorRenderTargetFormat_16_16_16_16_FLOAT:
|
||||
samples_0123.x = unpack_half_2x16_xe(packed_0123.x).x;
|
||||
samples_0123.y = unpack_half_2x16_xe(packed_0123.y).x;
|
||||
samples_0123.z = unpack_half_2x16_xe(packed_0123.z).x;
|
||||
samples_0123.w = unpack_half_2x16_xe(packed_0123.w).x;
|
||||
samples_4567.x = unpack_half_2x16_xe(packed_4567.x).x;
|
||||
samples_4567.y = unpack_half_2x16_xe(packed_4567.y).x;
|
||||
samples_4567.z = unpack_half_2x16_xe(packed_4567.z).x;
|
||||
samples_4567.w = unpack_half_2x16_xe(packed_4567.w).x;
|
||||
dont_flatten_xe if (source_alpha) {
|
||||
samples_0123.x = unpack_half_2x16_xe(packed_0123.x).y;
|
||||
samples_0123.y = unpack_half_2x16_xe(packed_0123.y).y;
|
||||
samples_0123.z = unpack_half_2x16_xe(packed_0123.z).y;
|
||||
samples_0123.w = unpack_half_2x16_xe(packed_0123.w).y;
|
||||
samples_4567.x = unpack_half_2x16_xe(packed_4567.x).y;
|
||||
samples_4567.y = unpack_half_2x16_xe(packed_4567.y).y;
|
||||
samples_4567.z = unpack_half_2x16_xe(packed_4567.z).y;
|
||||
samples_4567.w = unpack_half_2x16_xe(packed_4567.w).y;
|
||||
} else {
|
||||
samples_0123.x = unpack_half_2x16_xe(packed_0123.x).x;
|
||||
samples_0123.y = unpack_half_2x16_xe(packed_0123.y).x;
|
||||
samples_0123.z = unpack_half_2x16_xe(packed_0123.z).x;
|
||||
samples_0123.w = unpack_half_2x16_xe(packed_0123.w).x;
|
||||
samples_4567.x = unpack_half_2x16_xe(packed_4567.x).x;
|
||||
samples_4567.y = unpack_half_2x16_xe(packed_4567.y).x;
|
||||
samples_4567.z = unpack_half_2x16_xe(packed_4567.z).x;
|
||||
samples_4567.w = unpack_half_2x16_xe(packed_4567.w).x;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Treat as 32_32_FLOAT.
|
||||
samples_0123 = uint_bits_to_float_xe(packed_0123);
|
||||
samples_4567 = uint_bits_to_float_xe(packed_4567);
|
||||
dont_flatten_xe if (source_alpha) {
|
||||
// Missing alpha is 1.0 before MSAA averaging and exponent bias.
|
||||
samples_0123 = float_x4_xe(1.0f);
|
||||
samples_4567 = float_x4_xe(1.0f);
|
||||
} else {
|
||||
samples_0123 = uint_bits_to_float_xe(packed_0123);
|
||||
samples_4567 = uint_bits_to_float_xe(packed_4567);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -543,11 +604,11 @@ uint XeResolveEdramPixelStrideBytes(XeResolveInfo resolve_info) {
|
||||
}
|
||||
}
|
||||
|
||||
// For red/blue swapping for 64bpp, pre-add 4 to sample_address_bytes.
|
||||
void XeResolveLoad8RedPixelSamplesFromRaw(
|
||||
void XeResolveLoad8ScalarPixelSamplesFromRaw(
|
||||
param_byte_buffer_xe(xe_resolve_edram) param_next_after_byte_buffer_xe
|
||||
uint sample_address_bytes, uint pixel_stride_bytes,
|
||||
uint format_ints_log2, uint format, bool swap_32bpp,
|
||||
uint format_ints_log2, uint format, bool source_blue,
|
||||
bool source_alpha,
|
||||
out_param_xe(float4_xe, pixels_0123),
|
||||
out_param_xe(float4_xe, pixels_4567)) {
|
||||
uint4_xe packed_0123, packed_4567;
|
||||
@@ -575,12 +636,13 @@ uint XeResolveEdramPixelStrideBytes(XeResolveInfo resolve_info) {
|
||||
xe_resolve_edram, sample_address_bytes + 7u * pixel_stride_bytes);
|
||||
}
|
||||
dont_flatten_xe if (format_ints_log2 != 0u) {
|
||||
XeResolveUnpack64bpp8RedUnswappedSamples(packed_0123, packed_4567,
|
||||
format, pixels_0123,
|
||||
pixels_4567);
|
||||
XeResolveUnpack64bpp8ScalarSamples(packed_0123, packed_4567, format,
|
||||
source_alpha, pixels_0123,
|
||||
pixels_4567);
|
||||
} else {
|
||||
XeResolveUnpack32bpp8RedSamples(packed_0123, packed_4567, format,
|
||||
swap_32bpp, pixels_0123, pixels_4567);
|
||||
XeResolveUnpack32bpp8ScalarSamples(packed_0123, packed_4567, format,
|
||||
source_blue, source_alpha,
|
||||
pixels_0123, pixels_4567);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -849,22 +911,32 @@ uint XeResolveEdramPixelStrideBytes(XeResolveInfo resolve_info) {
|
||||
}
|
||||
}
|
||||
|
||||
void XeResolveLoad8RedColors(
|
||||
void XeResolveLoad8ScalarColors(
|
||||
param_byte_buffer_xe(xe_resolve_edram) param_next_after_byte_buffer_xe
|
||||
XeResolveInfo resolve_info, uint address_bytes,
|
||||
out_param_xe(float4_xe, pixels_0123),
|
||||
out_param_xe(float4_xe, pixels_4567)) {
|
||||
// D3D maps A8 to k_8 with LOW_BLUE.
|
||||
// k_8_A and k_8_B are still unknown, so keep the red/blue swap behavior.
|
||||
bool source_alpha =
|
||||
resolve_info.dest_swap && resolve_info.dest_format == kXenosFormat_8;
|
||||
bool source_blue = resolve_info.dest_swap && !source_alpha;
|
||||
uint pixel_stride_bytes = XeResolveEdramPixelStrideBytes(resolve_info);
|
||||
if (resolve_info.dest_swap && resolve_info.edram_format_ints_log2 != 0u) {
|
||||
// Likely want to load the blue part from the right half for 64bpp.
|
||||
if ((source_blue || source_alpha) &&
|
||||
resolve_info.edram_format_ints_log2 != 0u) {
|
||||
// The second dword of each 64bpp pixel holds blue and alpha.
|
||||
address_bytes += 4u;
|
||||
}
|
||||
XeResolveLoad8RedPixelSamplesFromRaw(
|
||||
// PWL encoding of 8_8_8_8_GAMMA only covers RGB. Alpha is stored as fixed
|
||||
// data, so it's not decoded.
|
||||
bool decode_pwl_gamma =
|
||||
XeResolveSourceUsesPWLGamma(resolve_info) && !source_alpha;
|
||||
XeResolveLoad8ScalarPixelSamplesFromRaw(
|
||||
pass_byte_buffer_xe(xe_resolve_edram) pass_next_after_byte_buffer_xe
|
||||
address_bytes, pixel_stride_bytes,
|
||||
resolve_info.edram_format_ints_log2, resolve_info.edram_format,
|
||||
resolve_info.dest_swap, pixels_0123, pixels_4567);
|
||||
dont_flatten_xe if (XeResolveSourceUsesPWLGamma(resolve_info)) {
|
||||
source_blue, source_alpha, pixels_0123, pixels_4567);
|
||||
dont_flatten_xe if (decode_pwl_gamma) {
|
||||
pixels_0123 = XePWLGammaToLinear4(pixels_0123);
|
||||
pixels_4567 = XePWLGammaToLinear4(pixels_4567);
|
||||
}
|
||||
@@ -874,13 +946,13 @@ uint XeResolveEdramPixelStrideBytes(XeResolveInfo resolve_info) {
|
||||
uint tile_row_stride_bytes = 4u * 80u * resolve_info.resolution_scale.x;
|
||||
exp_bias *= 0.5f;
|
||||
float4_xe msaa_resolve_pixels_0123, msaa_resolve_pixels_4567;
|
||||
XeResolveLoad8RedPixelSamplesFromRaw(
|
||||
XeResolveLoad8ScalarPixelSamplesFromRaw(
|
||||
pass_byte_buffer_xe(xe_resolve_edram) pass_next_after_byte_buffer_xe
|
||||
address_bytes + tile_row_stride_bytes, pixel_stride_bytes,
|
||||
resolve_info.edram_format_ints_log2, resolve_info.edram_format,
|
||||
resolve_info.dest_swap, msaa_resolve_pixels_0123,
|
||||
source_blue, source_alpha, msaa_resolve_pixels_0123,
|
||||
msaa_resolve_pixels_4567);
|
||||
dont_flatten_xe if (XeResolveSourceUsesPWLGamma(resolve_info)) {
|
||||
dont_flatten_xe if (decode_pwl_gamma) {
|
||||
msaa_resolve_pixels_0123 =
|
||||
XePWLGammaToLinear4(msaa_resolve_pixels_0123);
|
||||
msaa_resolve_pixels_4567 =
|
||||
@@ -892,14 +964,14 @@ uint XeResolveEdramPixelStrideBytes(XeResolveInfo resolve_info) {
|
||||
if (resolve_info.sample_select >= kXenosCopySampleSelect_0123) {
|
||||
uint sample_stride_bytes = 4u << resolve_info.edram_format_ints_log2;
|
||||
exp_bias *= 0.5f;
|
||||
XeResolveLoad8RedPixelSamplesFromRaw(
|
||||
XeResolveLoad8ScalarPixelSamplesFromRaw(
|
||||
pass_byte_buffer_xe(xe_resolve_edram)
|
||||
pass_next_after_byte_buffer_xe
|
||||
address_bytes + sample_stride_bytes, pixel_stride_bytes,
|
||||
resolve_info.edram_format_ints_log2, resolve_info.edram_format,
|
||||
resolve_info.dest_swap, msaa_resolve_pixels_0123,
|
||||
source_blue, source_alpha, msaa_resolve_pixels_0123,
|
||||
msaa_resolve_pixels_4567);
|
||||
dont_flatten_xe if (XeResolveSourceUsesPWLGamma(resolve_info)) {
|
||||
dont_flatten_xe if (decode_pwl_gamma) {
|
||||
msaa_resolve_pixels_0123 =
|
||||
XePWLGammaToLinear4(msaa_resolve_pixels_0123);
|
||||
msaa_resolve_pixels_4567 =
|
||||
@@ -907,14 +979,14 @@ uint XeResolveEdramPixelStrideBytes(XeResolveInfo resolve_info) {
|
||||
}
|
||||
pixels_0123 += msaa_resolve_pixels_0123;
|
||||
pixels_4567 += msaa_resolve_pixels_4567;
|
||||
XeResolveLoad8RedPixelSamplesFromRaw(
|
||||
XeResolveLoad8ScalarPixelSamplesFromRaw(
|
||||
pass_byte_buffer_xe(xe_resolve_edram)
|
||||
pass_next_after_byte_buffer_xe
|
||||
address_bytes + tile_row_stride_bytes + sample_stride_bytes,
|
||||
pixel_stride_bytes, resolve_info.edram_format_ints_log2,
|
||||
resolve_info.edram_format, resolve_info.dest_swap,
|
||||
resolve_info.edram_format, source_blue, source_alpha,
|
||||
msaa_resolve_pixels_0123, msaa_resolve_pixels_4567);
|
||||
dont_flatten_xe if (XeResolveSourceUsesPWLGamma(resolve_info)) {
|
||||
dont_flatten_xe if (decode_pwl_gamma) {
|
||||
msaa_resolve_pixels_0123 =
|
||||
XePWLGammaToLinear4(msaa_resolve_pixels_0123);
|
||||
msaa_resolve_pixels_4567 =
|
||||
|
||||
@@ -35,7 +35,7 @@ entry_inputs_end_code_begin_compute_xe
|
||||
}
|
||||
uint2_xe pixel_index = in_global_thread_id_xe.xy << uint2_xe(3u, 0u);
|
||||
float4_xe pixels_0123, pixels_4567;
|
||||
XeResolveLoad8RedColors(
|
||||
XeResolveLoad8ScalarColors(
|
||||
pass_byte_buffer_xe(xe_resolve_edram) pass_next_after_byte_buffer_xe
|
||||
resolve_info,
|
||||
XeResolveColorCopySourcePixelAddressBytesYHalfPixelOffsetFilling(
|
||||
@@ -53,6 +53,7 @@ entry_inputs_end_code_begin_compute_xe
|
||||
pixels_0123.x = pixels_0123.y;
|
||||
}
|
||||
// Convert to R8.
|
||||
// Pack the selected component while loading the samples to R8.
|
||||
// TODO(Triang3l): Investigate formats 8_A and 8_B.
|
||||
byte_buffer_align8_store8_xe(
|
||||
xe_resolve_dest, XeResolveDestPixelAddress(resolve_info, pixel_index, 0u),
|
||||
|
||||
Reference in New Issue
Block a user