Files
Xenia-Canary/src/xenia/gpu/shaders/resolve.xesli
goldislead d119505289 [GPU] Texture integer scaling fetches; 8_8_8_8_GAMMA resolve
Integer num_format fetches now get their scale CPU-side instead of trying to guess in the shader. This is authoritative; no cvar. Both translators now use texture_integer_scale_bits after signs/gamma and before exponent bias. This alone fixes black screens and a bunch of rendering bugs across at least several dozen titles.

This new information lives in the updated FormatInfo table, including fixed component widths.

Resolve also has two new fixes.

8_8_8_8_GAMMA EDRAM sources can now decode through the PWL curve while still in linear space, before MSAA resolve or format conversion, then re-encoded for gamma destinations. This is also now default enabled via gamma_decode_pwl_resolve and has improved blowout in at least 4 titles, with no obvious regressions thus far.

Full resolve can also now pack fixed destinations according to copy_dest_number.
2026-07-06 20:51:02 +02:00

990 lines
44 KiB
Plaintext

/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2022 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_GPU_SHADERS_RESOLVE_XESLI_
#define XENIA_GPU_SHADERS_RESOLVE_XESLI_
#include "edram.xesli"
#include "pixel_formats.xesli"
#include "texture_address.xesli"
#define kXenosCopySampleSelect_0 0u
#define kXenosCopySampleSelect_1 1u
#define kXenosCopySampleSelect_2 2u
#define kXenosCopySampleSelect_3 3u
#define kXenosCopySampleSelect_01 4u
#define kXenosCopySampleSelect_23 5u
#define kXenosCopySampleSelect_0123 6u
push_const_begin_xe(b0, space0)
#ifdef XE_RESOLVE_CLEAR
uint2_xe xe_resolve_clear_value;
#endif
// xe::gpu::draw_util::ResolveEdramInfo.
uint xe_resolve_edram_info;
// xe::gpu::draw_util::ResolveCoordinateInfo.
uint xe_resolve_coordinate_info;
#ifndef XE_RESOLVE_CLEAR
// Sanitized RB_COPY_DEST_INFO.
uint xe_resolve_dest_info;
// xe::gpu::draw_util::ResolveCopyDestCoordinateInfo.
uint xe_resolve_dest_coordinate_info;
#ifndef XE_RESOLVE_RESOLUTION_SCALED
uint xe_resolve_dest_base;
#endif
#endif
push_const_end_xe
#define XE_RESOLVE_PUSH_CONST_BINDING push_const_binding_xe(buffer(0))
#ifndef XE_RESOLVE_CLEAR
#if XE_RESOLVE_COPY_EDRAM_BYTE_BUFFER_ALIGNMENT == 4
#define XE_RESOLVE_COPY_EDRAM_BYTE_BUFFER_DECLARE_MACRO \
byte_buffer_align4_declare_xe
#elif XE_RESOLVE_COPY_EDRAM_BYTE_BUFFER_ALIGNMENT == 8
#define XE_RESOLVE_COPY_EDRAM_BYTE_BUFFER_DECLARE_MACRO \
byte_buffer_align8_declare_xe
#elif XE_RESOLVE_COPY_EDRAM_BYTE_BUFFER_ALIGNMENT == 16
#define XE_RESOLVE_COPY_EDRAM_BYTE_BUFFER_DECLARE_MACRO \
byte_buffer_align16_declare_xe
#endif
#ifdef XE_RESOLVE_COPY_EDRAM_BYTE_BUFFER_DECLARE_MACRO
XE_RESOLVE_COPY_EDRAM_BYTE_BUFFER_DECLARE_MACRO(xe_resolve_edram, set=0,
binding=0, t0, space0)
#endif
#define XE_RESOLVE_COPY_EDRAM_BINDING \
byte_buffer_binding_xe(xe_resolve_edram, buffer(2))
#endif
struct XeResolveInfo {
uint edram_pitch_tiles;
uint edram_msaa_samples;
// Always false for non-one-to-one resolve.
bool edram_is_depth;
uint edram_base_tiles;
uint edram_format;
uint edram_format_ints_log2;
bool decode_pwl_gamma;
uint2_xe resolution_scale;
uint2_xe half_pixel_offset_fill_source;
uint2_xe edram_offset_scaled;
uint width_div_8_scaled;
#ifdef XE_RESOLVE_CLEAR
uint2_xe clear_value;
#else
uint dest_endian_128;
bool dest_is_array;
uint dest_slice;
uint dest_format;
uint dest_num_format;
float dest_exp_bias_factor;
bool dest_swap;
uint dest_row_pitch_macro_tiles;
uint dest_slice_pitch_3d_macro_tiles;
uint2_xe dest_xy_offset_scaled;
uint sample_select;
uint dest_base;
#endif // XE_RESOLVE_CLEAR
};
XeResolveInfo XeResolveGetInfo(param_push_consts_xe) {
XeResolveInfo resolve_info;
uint edram_info = push_const_xe(xe_resolve_edram_info);
uint coordinate_info = push_const_xe(xe_resolve_coordinate_info);
resolve_info.edram_pitch_tiles = edram_info & ((1u << 10u) - 1u);
resolve_info.edram_msaa_samples = (edram_info >> 10u) & ((1u << 2u) - 1u);
resolve_info.edram_is_depth = (edram_info & (1u << 12u)) != 0u;
resolve_info.edram_base_tiles = (edram_info >> 13u) & ((1u << 11u) - 1u);
resolve_info.edram_format = (edram_info >> 24u) & ((1u << 4u) - 1u);
resolve_info.edram_format_ints_log2 = (edram_info >> 28u) & 1u;
resolve_info.decode_pwl_gamma = (edram_info & (1u << 30u)) != 0u;
#ifdef XE_RESOLVE_RESOLUTION_SCALED
resolve_info.resolution_scale =
(uint_x2_xe(coordinate_info) >> uint2_xe(16u, 19u)) & 7u;
if ((edram_info & (1u << 29u)) != 0u) {
resolve_info.half_pixel_offset_fill_source =
resolve_info.resolution_scale >> 1u;
} else {
resolve_info.half_pixel_offset_fill_source = uint_x2_xe(0u);
}
#else
resolve_info.resolution_scale = uint_x2_xe(1u);
resolve_info.half_pixel_offset_fill_source = uint_x2_xe(0u);
#endif
resolve_info.edram_offset_scaled =
(((uint_x2_xe(coordinate_info) >> uint2_xe(0u, 4u)) &
((uint_x2_xe(1u) << uint2_xe(4u, 1u)) - 1u)) <<
3u) *
resolve_info.resolution_scale;
resolve_info.width_div_8_scaled =
((coordinate_info >> 5u) & ((1u << 11u) - 1u)) *
resolve_info.resolution_scale.x;
#ifdef XE_RESOLVE_CLEAR
resolve_info.clear_value = push_const_xe(xe_resolve_clear_value);
#else
uint dest_info = push_const_xe(xe_resolve_dest_info);
uint dest_coordinate_info =
push_const_xe(xe_resolve_dest_coordinate_info);
resolve_info.dest_endian_128 = dest_info & ((1u << 3u) - 1u);
resolve_info.dest_is_array = (dest_info & (1u << 3u)) != 0u;
resolve_info.dest_slice = (dest_info >> 4u) & ((1u << 3u) - 1u);
resolve_info.dest_format = (dest_info >> 7u) & ((1u << 6u) - 1u);
resolve_info.dest_num_format = (dest_info >> 13u) & ((1u << 3u) - 1u);
resolve_info.dest_exp_bias_factor = int_bits_to_float_xe(
(int(dest_info) << (32 - (16 + 6)) >> (32 - 6) << 23) +
float_bits_to_int_xe(1.0f));
resolve_info.dest_swap = (dest_info & (1u << 24u)) != 0u;
resolve_info.dest_row_pitch_macro_tiles =
dest_coordinate_info & ((1u << 10u) - 1u);
resolve_info.dest_slice_pitch_3d_macro_tiles =
((dest_coordinate_info >> 10u) & ((1u << 10u) - 1u)) <<
(5 - XENOS_TEXTURE_MACRO_TILE_HEIGHT_3D_LOG2);
resolve_info.dest_xy_offset_scaled =
(((uint_x2_xe(dest_coordinate_info) >> uint2_xe(20u, 24u)) &
((1u << 4u) - 1u)) <<
3u) *
resolve_info.resolution_scale;
resolve_info.sample_select =
(dest_coordinate_info >> 28u) & ((1u << 3u) - 1u);
#ifndef XE_RESOLVE_RESOLUTION_SCALED
resolve_info.dest_base = push_const_xe(xe_resolve_dest_base);
#else
resolve_info.dest_base = 0;
#endif
#endif // XE_RESOLVE_CLEAR
return resolve_info;
}
uint XeResolveEdramPixelStrideBytes(XeResolveInfo resolve_info) {
return 4u << (resolve_info.edram_format_ints_log2 +
uint(resolve_info.edram_msaa_samples >= kXenosMsaaSamples_4X));
}
#ifndef XE_RESOLVE_CLEAR
uint XeResolveDestPixelAddress(const XeResolveInfo resolve_info,
uint2_xe host_position,
const uint bytes_per_block_log2) {
host_position += resolve_info.dest_xy_offset_scaled;
uint address;
uint2_xe guest_position = host_position;
#ifdef XE_RESOLVE_RESOLUTION_SCALED
const XeniaTextureResolutionScaledAddressing
resolution_scaled_addressing =
XeniaTextureGetResolutionScaledAddressing(
host_position.xy, resolve_info.resolution_scale,
bytes_per_block_log2);
guest_position = resolution_scaled_addressing.guest_group_origin;
#endif
dont_flatten_xe if (resolve_info.dest_is_array) {
address = uint(XenosTextureTiledAddress3D(
int3_xe(uint3_xe(guest_position, resolve_info.dest_slice)),
resolve_info.dest_row_pitch_macro_tiles,
resolve_info.dest_slice_pitch_3d_macro_tiles, bytes_per_block_log2));
} else {
address = uint(XenosTextureTiledAddress2D(
int2_xe(guest_position), resolve_info.dest_row_pitch_macro_tiles,
bytes_per_block_log2));
}
#ifdef XE_RESOLVE_RESOLUTION_SCALED
address = address * (resolve_info.resolution_scale.x *
resolve_info.resolution_scale.y) +
resolution_scaled_addressing.host_byte_offset_in_guest_group;
#endif
address += resolve_info.dest_base;
return address;
}
// XOR to apply to the byte address to flip the bits corresponding to the
// given X coordinate bits within the macro tile width, or with resolution
// scaling, within XeniaTextureResolutionScaledGroupBlocks.x.
// Addition is recommended instead of XOR if the bits are known to be 0 in the
// original address, so the host GPU driver can optimize it into a constant
// store offset if available in the host hardware shader instruction set
// architecture.
uint XeResolveLocalXAddressXor(const uint x,
const uint bytes_per_block_log2) {
#ifdef XE_RESOLVE_RESOLUTION_SCALED
return x << bytes_per_block_log2;
#else
return uint(XenosTextureTiledAddressXInMacroXor(int(x),
bytes_per_block_log2));
#endif
}
#define kXenosCopySampleSelect_0 0u
#define kXenosCopySampleSelect_1 1u
#define kXenosCopySampleSelect_2 2u
#define kXenosCopySampleSelect_3 3u
#define kXenosCopySampleSelect_01 4u
#define kXenosCopySampleSelect_23 5u
#define kXenosCopySampleSelect_0123 6u
uint XeResolveFirstSampleIndex(uint sample_select) {
uint sample_index;
if (sample_select <= kXenosCopySampleSelect_3) {
sample_index = sample_select;
} else if (sample_select == kXenosCopySampleSelect_23) {
sample_index = 2u;
} else {
sample_index = 0u;
}
return sample_index;
}
// Offset to the first sample to participate in averaging (or the sample to be
// copied if not averaging).
uint XeResolveColorCopySourcePixelAddressBytesYHalfPixelOffsetFilling(
XeResolveInfo resolve_info, uint2_xe pixel_index) {
return XeEdramOffsetBytes(
uint2_xe(pixel_index.x,
max(pixel_index.y,
resolve_info.half_pixel_offset_fill_source.y)) +
resolve_info.edram_offset_scaled,
resolve_info.edram_base_tiles, true, resolve_info.edram_pitch_tiles,
resolve_info.edram_msaa_samples, false,
resolve_info.edram_format_ints_log2,
XeResolveFirstSampleIndex(resolve_info.sample_select),
resolve_info.resolution_scale);
}
// Not using arrays for multi-pixel function arguments because indexable temps
// are generated for them by FXC, that may be compiled unoptimally by the host
// GPU driver.
void XeResolveUnpack32bpp2Samples(
uint2_xe packed, uint format, out_param_xe(float4_xe, sample_0),
out_param_xe(float4_xe, sample_1)) {
switch (format) {
case kXenosColorRenderTargetFormat_8_8_8_8:
case kXenosColorRenderTargetFormat_8_8_8_8_GAMMA:
sample_0 = XeUnpackR8G8B8A8UNorm(packed.x);
sample_1 = XeUnpackR8G8B8A8UNorm(packed.y);
break;
case kXenosColorRenderTargetFormat_2_10_10_10:
case kXenosColorRenderTargetFormat_2_10_10_10_AS_10_10_10_10:
sample_0 = XeUnpackR10G10B10A2UNorm(packed.x);
sample_1 = XeUnpackR10G10B10A2UNorm(packed.y);
break;
case kXenosColorRenderTargetFormat_2_10_10_10_FLOAT:
case kXenosColorRenderTargetFormat_2_10_10_10_FLOAT_AS_16_16_16_16:
sample_0 = XeUnpackR10G10B10A2Float(packed.x);
sample_1 = XeUnpackR10G10B10A2Float(packed.y);
break;
case kXenosColorRenderTargetFormat_16_16:
sample_0 = float4_xe(XeUnpackR16G16Edram(packed.x), 0.0f, 0.0f);
sample_1 = float4_xe(XeUnpackR16G16Edram(packed.y), 0.0f, 0.0f);
break;
case kXenosColorRenderTargetFormat_16_16_FLOAT:
sample_0 = float4_xe(unpack_half_2x16_xe(packed.x), 0.0f, 0.0f);
sample_1 = float4_xe(unpack_half_2x16_xe(packed.y), 0.0f, 0.0f);
break;
default:
// Treat as 32_FLOAT.
sample_0 = float2_xe(uint_bits_to_float_xe(packed.x), 0.0f).xyyy;
sample_1 = float2_xe(uint_bits_to_float_xe(packed.y), 0.0f).xyyy;
break;
}
}
void XeResolveUnpack32bpp4Samples(
uint4_xe packed, uint format, out_param_xe(float4_xe, sample_0),
out_param_xe(float4_xe, sample_1), out_param_xe(float4_xe, sample_2),
out_param_xe(float4_xe, sample_3)) {
switch (format) {
case kXenosColorRenderTargetFormat_8_8_8_8:
case kXenosColorRenderTargetFormat_8_8_8_8_GAMMA:
sample_0 = XeUnpackR8G8B8A8UNorm(packed.x);
sample_1 = XeUnpackR8G8B8A8UNorm(packed.y);
sample_2 = XeUnpackR8G8B8A8UNorm(packed.z);
sample_3 = XeUnpackR8G8B8A8UNorm(packed.w);
break;
case kXenosColorRenderTargetFormat_2_10_10_10:
case kXenosColorRenderTargetFormat_2_10_10_10_AS_10_10_10_10:
sample_0 = XeUnpackR10G10B10A2UNorm(packed.x);
sample_1 = XeUnpackR10G10B10A2UNorm(packed.y);
sample_2 = XeUnpackR10G10B10A2UNorm(packed.z);
sample_3 = XeUnpackR10G10B10A2UNorm(packed.w);
break;
case kXenosColorRenderTargetFormat_2_10_10_10_FLOAT:
case kXenosColorRenderTargetFormat_2_10_10_10_FLOAT_AS_16_16_16_16:
sample_0 = XeUnpackR10G10B10A2Float(packed.x);
sample_1 = XeUnpackR10G10B10A2Float(packed.y);
sample_2 = XeUnpackR10G10B10A2Float(packed.z);
sample_3 = XeUnpackR10G10B10A2Float(packed.w);
break;
case kXenosColorRenderTargetFormat_16_16:
sample_0 = float4_xe(XeUnpackR16G16Edram(packed.x), 0.0f, 0.0f);
sample_1 = float4_xe(XeUnpackR16G16Edram(packed.y), 0.0f, 0.0f);
sample_2 = float4_xe(XeUnpackR16G16Edram(packed.z), 0.0f, 0.0f);
sample_3 = float4_xe(XeUnpackR16G16Edram(packed.w), 0.0f, 0.0f);
break;
case kXenosColorRenderTargetFormat_16_16_FLOAT:
sample_0 = float4_xe(unpack_half_2x16_xe(packed.x), 0.0f, 0.0f);
sample_1 = float4_xe(unpack_half_2x16_xe(packed.y), 0.0f, 0.0f);
sample_2 = float4_xe(unpack_half_2x16_xe(packed.z), 0.0f, 0.0f);
sample_3 = float4_xe(unpack_half_2x16_xe(packed.w), 0.0f, 0.0f);
break;
default:
// Treat as 32_FLOAT.
sample_0 = float2_xe(uint_bits_to_float_xe(packed.x), 0.0f).xyyy;
sample_1 = float2_xe(uint_bits_to_float_xe(packed.y), 0.0f).xyyy;
sample_2 = float2_xe(uint_bits_to_float_xe(packed.z), 0.0f).xyyy;
sample_3 = float2_xe(uint_bits_to_float_xe(packed.w), 0.0f).xyyy;
break;
}
}
void XeResolveUnpack32bpp8RedSamples(
uint4_xe packed_0123, uint4_xe packed_4567, uint format, bool swap,
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;
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_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_16_16:
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;
break;
default:
// Treat as 32_FLOAT.
samples_0123 = uint_bits_to_float_xe(packed_0123);
samples_4567 = uint_bits_to_float_xe(packed_4567);
break;
}
}
void XeResolveUnpack64bpp2Samples(
uint4_xe packed, uint format, out_param_xe(float4_xe, sample_0),
out_param_xe(float4_xe, sample_1)) {
switch (format) {
case kXenosColorRenderTargetFormat_16_16_16_16:
sample_0 = XeUnpackR16G16B16A16Edram(packed.xy);
sample_1 = XeUnpackR16G16B16A16Edram(packed.zw);
break;
case kXenosColorRenderTargetFormat_16_16_16_16_FLOAT:
sample_0.xy = unpack_half_2x16_xe(packed.x);
sample_0.zw = unpack_half_2x16_xe(packed.y);
sample_1.xy = unpack_half_2x16_xe(packed.z);
sample_1.zw = unpack_half_2x16_xe(packed.w);
break;
default:
// Treat as 32_32_FLOAT.
sample_0 = float4_xe(uint_bits_to_float_xe(packed.xy), 0.0f, 0.0f);
sample_1 = float4_xe(uint_bits_to_float_xe(packed.zw), 0.0f, 0.0f);
break;
}
}
void XeResolveUnpack64bpp4Samples(
uint4_xe packed_01, uint4_xe packed_23, uint format,
out_param_xe(float4_xe, sample_0), out_param_xe(float4_xe, sample_1),
out_param_xe(float4_xe, sample_2), out_param_xe(float4_xe, sample_3)) {
switch (format) {
case kXenosColorRenderTargetFormat_16_16_16_16:
sample_0 = XeUnpackR16G16B16A16Edram(packed_01.xy);
sample_1 = XeUnpackR16G16B16A16Edram(packed_01.zw);
sample_2 = XeUnpackR16G16B16A16Edram(packed_23.xy);
sample_3 = XeUnpackR16G16B16A16Edram(packed_23.zw);
break;
case kXenosColorRenderTargetFormat_16_16_16_16_FLOAT:
sample_0.xy = unpack_half_2x16_xe(packed_01.x);
sample_0.zw = unpack_half_2x16_xe(packed_01.y);
sample_1.xy = unpack_half_2x16_xe(packed_01.z);
sample_1.zw = unpack_half_2x16_xe(packed_01.w);
sample_2.xy = unpack_half_2x16_xe(packed_23.x);
sample_2.zw = unpack_half_2x16_xe(packed_23.y);
sample_3.xy = unpack_half_2x16_xe(packed_23.z);
sample_3.zw = unpack_half_2x16_xe(packed_23.w);
break;
default:
// Treat as 32_32_FLOAT.
sample_0 = float4_xe(uint_bits_to_float_xe(packed_01.xy), 0.0f, 0.0f);
sample_1 = float4_xe(uint_bits_to_float_xe(packed_01.zw), 0.0f, 0.0f);
sample_2 = float4_xe(uint_bits_to_float_xe(packed_23.xy), 0.0f, 0.0f);
sample_3 = float4_xe(uint_bits_to_float_xe(packed_23.zw), 0.0f, 0.0f);
break;
}
}
void XeResolveUnpack64bpp8RedUnswappedSamples(
uint4_xe packed_0123, uint4_xe packed_4567, uint format,
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_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;
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);
break;
}
}
#if XE_RESOLVE_COPY_EDRAM_BYTE_BUFFER_ALIGNMENT == 4
void XeResolveLoad2RGBAUnswappedPixelSamplesFromRaw(
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, out_param_xe(float4_xe, pixel_0),
out_param_xe(float4_xe, pixel_1)) {
dont_flatten_xe if (format_ints_log2 != 0u) {
uint4_xe packed;
dont_flatten_xe if (pixel_stride_bytes == 8u) {
packed = byte_buffer_align4_load16u_xe(
xe_resolve_edram, sample_address_bytes);
} else {
packed.xy = byte_buffer_align4_load8u_xe(
xe_resolve_edram, sample_address_bytes);
packed.zw = byte_buffer_align4_load8u_xe(
xe_resolve_edram, sample_address_bytes + pixel_stride_bytes);
}
XeResolveUnpack64bpp2Samples(packed, format, pixel_0, pixel_1);
} else {
uint2_xe packed;
dont_flatten_xe if (pixel_stride_bytes == 4u) {
packed = byte_buffer_align4_load8u_xe(
xe_resolve_edram, sample_address_bytes);
} else {
packed.x = byte_buffer_align4_load4_xe(
xe_resolve_edram, sample_address_bytes);
packed.y = byte_buffer_align4_load4_xe(
xe_resolve_edram, sample_address_bytes + pixel_stride_bytes);
}
XeResolveUnpack32bpp2Samples(packed, format, pixel_0, pixel_1);
}
}
void XeResolveLoad4RGBAUnswappedPixelSamplesFromRaw(
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, out_param_xe(float4_xe, pixel_0),
out_param_xe(float4_xe, pixel_1), out_param_xe(float4_xe, pixel_2),
out_param_xe(float4_xe, pixel_3)) {
dont_flatten_xe if (format_ints_log2 != 0u) {
uint4_xe packed_01, packed_23;
dont_flatten_xe if (pixel_stride_bytes == 8u) {
packed_01 = byte_buffer_align4_load16u_xe(
xe_resolve_edram, sample_address_bytes);
packed_23 = byte_buffer_align4_load16u_xe(
xe_resolve_edram, sample_address_bytes + 16u);
} else {
packed_01.xy = byte_buffer_align4_load8u_xe(
xe_resolve_edram, sample_address_bytes);
packed_01.zw = byte_buffer_align4_load8u_xe(
xe_resolve_edram, sample_address_bytes + pixel_stride_bytes);
packed_23.xy = byte_buffer_align4_load8u_xe(
xe_resolve_edram, sample_address_bytes + 2u * pixel_stride_bytes);
packed_23.zw = byte_buffer_align4_load8u_xe(
xe_resolve_edram, sample_address_bytes + 3u * pixel_stride_bytes);
}
XeResolveUnpack64bpp4Samples(packed_01, packed_23, format, pixel_0,
pixel_1, pixel_2, pixel_3);
} else {
uint4_xe packed;
dont_flatten_xe if (pixel_stride_bytes == 4u) {
packed = byte_buffer_align4_load16u_xe(
xe_resolve_edram, sample_address_bytes);
} else {
packed.x = byte_buffer_align4_load4_xe(
xe_resolve_edram, sample_address_bytes);
packed.y = byte_buffer_align4_load4_xe(
xe_resolve_edram, sample_address_bytes + pixel_stride_bytes);
packed.z = byte_buffer_align4_load4_xe(
xe_resolve_edram, sample_address_bytes + 2u * pixel_stride_bytes);
packed.w = byte_buffer_align4_load4_xe(
xe_resolve_edram, sample_address_bytes + 3u * pixel_stride_bytes);
}
XeResolveUnpack32bpp4Samples(packed, format, pixel_0, pixel_1, pixel_2,
pixel_3);
}
}
// For red/blue swapping for 64bpp, pre-add 4 to sample_address_bytes.
void XeResolveLoad8RedPixelSamplesFromRaw(
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,
out_param_xe(float4_xe, pixels_0123),
out_param_xe(float4_xe, pixels_4567)) {
uint4_xe packed_0123, packed_4567;
dont_flatten_xe if (pixel_stride_bytes == 4u) {
packed_0123 = byte_buffer_align4_load16u_xe(
xe_resolve_edram, sample_address_bytes);
packed_4567 = byte_buffer_align4_load16u_xe(
xe_resolve_edram, sample_address_bytes + 16u);
} else {
packed_0123.x = byte_buffer_align4_load4_xe(
xe_resolve_edram, sample_address_bytes);
packed_0123.y = byte_buffer_align4_load4_xe(
xe_resolve_edram, sample_address_bytes + pixel_stride_bytes);
packed_0123.z = byte_buffer_align4_load4_xe(
xe_resolve_edram, sample_address_bytes + 2u * pixel_stride_bytes);
packed_0123.w = byte_buffer_align4_load4_xe(
xe_resolve_edram, sample_address_bytes + 3u * pixel_stride_bytes);
packed_4567.x = byte_buffer_align4_load4_xe(
xe_resolve_edram, sample_address_bytes + 4u * pixel_stride_bytes);
packed_4567.y = byte_buffer_align4_load4_xe(
xe_resolve_edram, sample_address_bytes + 5u * pixel_stride_bytes);
packed_4567.z = byte_buffer_align4_load4_xe(
xe_resolve_edram, sample_address_bytes + 6u * pixel_stride_bytes);
packed_4567.w = byte_buffer_align4_load4_xe(
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);
} else {
XeResolveUnpack32bpp8RedSamples(packed_0123, packed_4567, format,
swap_32bpp, pixels_0123, pixels_4567);
}
}
// Gamma RTs store linear 10 bit color through an 8 bit PWL curve.
// Host sRGB is not a substitute. Some titles appear overexposed if full
// 8_8_8_8_GAMMA resolves average the encoded bytes directly (5345085D,
// 45410934), so we decode before MSAA averaging and encode again only
// for compatible 8_8_8_8 destinations.
float XePWLGammaToLinear(float gamma) {
gamma = saturate_xe(gamma);
float scale;
float offset;
if (gamma >= 96.0f / 255.0f) {
if (gamma >= 192.0f / 255.0f) {
scale = 8.0f / 1024.0f;
offset = -1024.0f;
} else {
scale = 4.0f / 1024.0f;
offset = -256.0f;
}
} else {
if (gamma >= 64.0f / 255.0f) {
scale = 2.0f / 1024.0f;
offset = -64.0f;
} else {
scale = 1.0f / 1024.0f;
offset = 0.0f;
}
}
float linear_value = gamma * (255.0f * 1024.0f) * scale + offset;
linear_value += trunc(linear_value * scale);
return linear_value * (1.0f / 1023.0f);
}
float3_xe XePWLGammaToLinear3(float3_xe gamma) {
return float3_xe(XePWLGammaToLinear(gamma.x),
XePWLGammaToLinear(gamma.y),
XePWLGammaToLinear(gamma.z));
}
float4_xe XePWLGammaToLinear4(float4_xe gamma) {
return float4_xe(XePWLGammaToLinear(gamma.x),
XePWLGammaToLinear(gamma.y),
XePWLGammaToLinear(gamma.z),
XePWLGammaToLinear(gamma.w));
}
float XeLinearToPWLGamma(float linear_value) {
linear_value = saturate_xe(linear_value);
float scale;
float offset;
if (linear_value >= 128.0f / 1023.0f) {
if (linear_value >= 512.0f / 1023.0f) {
scale = 1023.0f / 8.0f;
offset = 128.0f / 255.0f;
} else {
scale = 1023.0f / 4.0f;
offset = 64.0f / 255.0f;
}
} else {
if (linear_value >= 64.0f / 1023.0f) {
scale = 1023.0f / 2.0f;
offset = 32.0f / 255.0f;
} else {
scale = 1023.0f;
offset = 0.0f;
}
}
return trunc(linear_value * scale) * (1.0f / 255.0f) + offset;
}
float3_xe XeLinearToPWLGamma3(float3_xe linear_value) {
return float3_xe(XeLinearToPWLGamma(linear_value.x),
XeLinearToPWLGamma(linear_value.y),
XeLinearToPWLGamma(linear_value.z));
}
bool XeResolveSourceUsesPWLGamma(XeResolveInfo resolve_info) {
return resolve_info.decode_pwl_gamma &&
resolve_info.edram_format ==
kXenosColorRenderTargetFormat_8_8_8_8_GAMMA;
}
bool XeResolveDestStoresPWLGamma(XeResolveInfo resolve_info) {
// Resolve constants don't carry a destination gamma bit. Treat an
// unsigned 8_8_8_8 destination as PWL gamma storage.
bool dest_number_is_unorm =
resolve_info.dest_num_format ==
kXenosSurfaceNumberFormat_UnsignedRepeatingFraction;
bool dest_is_8888 =
resolve_info.dest_format == kXenosFormat_8_8_8_8 ||
resolve_info.dest_format == kXenosFormat_8_8_8_8_A ||
resolve_info.dest_format ==
kXenosFormat_8_8_8_8_AS_16_16_16_16;
return dest_number_is_unorm && dest_is_8888;
}
void XeResolvePWLGammaToLinearRGB(inout_param_xe(float4_xe, pixel)) {
pixel.rgb = XePWLGammaToLinear3(pixel.rgb);
}
void XeResolveLinearToPWLGammaRGB(inout_param_xe(float4_xe, pixel)) {
pixel.rgb = XeLinearToPWLGamma3(pixel.rgb);
}
void XeResolveDecodePWLGammaSource(
XeResolveInfo resolve_info, inout_param_xe(float4_xe, pixel)) {
// Source gamma is RGB only. 8_8_8_8_GAMMA still stores alpha as ordinary
// fixed data, so alpha needs to stay with normal resolve.
dont_flatten_xe if (XeResolveSourceUsesPWLGamma(resolve_info)) {
XeResolvePWLGammaToLinearRGB(pixel);
}
}
void XeResolveEncodePWLGammaDest(
XeResolveInfo resolve_info, inout_param_xe(float4_xe, pixel)) {
// Only re-encode when the source was PWL gamma and the destination is the
// 8_8_8_8 UNORM storage we treat as the same PWL byte stream.
dont_flatten_xe if (XeResolveSourceUsesPWLGamma(resolve_info) &&
XeResolveDestStoresPWLGamma(resolve_info)) {
XeResolveLinearToPWLGammaRGB(pixel);
}
}
void XeResolveLoad2RGBAColors(
param_byte_buffer_xe(xe_resolve_edram) param_next_after_byte_buffer_xe
XeResolveInfo resolve_info, uint address_bytes,
out_param_xe(float4_xe, pixel_0), out_param_xe(float4_xe, pixel_1)) {
uint pixel_stride_bytes = XeResolveEdramPixelStrideBytes(resolve_info);
XeResolveLoad2RGBAUnswappedPixelSamplesFromRaw(
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,
pixel_0, pixel_1);
XeResolveDecodePWLGammaSource(resolve_info, pixel_0);
XeResolveDecodePWLGammaSource(resolve_info, pixel_1);
float exp_bias = resolve_info.dest_exp_bias_factor;
dont_flatten_xe
if (resolve_info.sample_select >= kXenosCopySampleSelect_01) {
uint tile_row_stride_bytes = 4u * 80u * resolve_info.resolution_scale.x;
exp_bias *= 0.5f;
float4_xe msaa_resolve_pixel_0, msaa_resolve_pixel_1;
XeResolveLoad2RGBAUnswappedPixelSamplesFromRaw(
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,
msaa_resolve_pixel_0, msaa_resolve_pixel_1);
XeResolveDecodePWLGammaSource(resolve_info, msaa_resolve_pixel_0);
XeResolveDecodePWLGammaSource(resolve_info, msaa_resolve_pixel_1);
pixel_0 += msaa_resolve_pixel_0;
pixel_1 += msaa_resolve_pixel_1;
dont_flatten_xe
if (resolve_info.sample_select >= kXenosCopySampleSelect_0123) {
uint sample_stride_bytes = 4u << resolve_info.edram_format_ints_log2;
exp_bias *= 0.5f;
XeResolveLoad2RGBAUnswappedPixelSamplesFromRaw(
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,
msaa_resolve_pixel_0, msaa_resolve_pixel_1);
XeResolveDecodePWLGammaSource(resolve_info, msaa_resolve_pixel_0);
XeResolveDecodePWLGammaSource(resolve_info, msaa_resolve_pixel_1);
pixel_0 += msaa_resolve_pixel_0;
pixel_1 += msaa_resolve_pixel_1;
XeResolveLoad2RGBAUnswappedPixelSamplesFromRaw(
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, msaa_resolve_pixel_0,
msaa_resolve_pixel_1);
XeResolveDecodePWLGammaSource(resolve_info, msaa_resolve_pixel_0);
XeResolveDecodePWLGammaSource(resolve_info, msaa_resolve_pixel_1);
pixel_0 += msaa_resolve_pixel_0;
pixel_1 += msaa_resolve_pixel_1;
}
}
pixel_0 *= exp_bias;
pixel_1 *= exp_bias;
XeResolveEncodePWLGammaDest(resolve_info, pixel_0);
XeResolveEncodePWLGammaDest(resolve_info, pixel_1);
dont_flatten_xe if (resolve_info.dest_swap) {
pixel_0 = pixel_0.bgra;
pixel_1 = pixel_1.bgra;
}
}
void XeResolveLoad4RGBAColors(
param_byte_buffer_xe(xe_resolve_edram) param_next_after_byte_buffer_xe
XeResolveInfo resolve_info, uint address_bytes,
out_param_xe(float4_xe, pixel_0), out_param_xe(float4_xe, pixel_1),
out_param_xe(float4_xe, pixel_2), out_param_xe(float4_xe, pixel_3)) {
uint pixel_stride_bytes = XeResolveEdramPixelStrideBytes(resolve_info);
XeResolveLoad4RGBAUnswappedPixelSamplesFromRaw(
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,
pixel_0, pixel_1, pixel_2, pixel_3);
XeResolveDecodePWLGammaSource(resolve_info, pixel_0);
XeResolveDecodePWLGammaSource(resolve_info, pixel_1);
XeResolveDecodePWLGammaSource(resolve_info, pixel_2);
XeResolveDecodePWLGammaSource(resolve_info, pixel_3);
float exp_bias = resolve_info.dest_exp_bias_factor;
dont_flatten_xe
if (resolve_info.sample_select >= kXenosCopySampleSelect_01) {
uint tile_row_stride_bytes = 4u * 80u * resolve_info.resolution_scale.x;
exp_bias *= 0.5f;
float4_xe msaa_resolve_pixel_0;
float4_xe msaa_resolve_pixel_1;
float4_xe msaa_resolve_pixel_2;
float4_xe msaa_resolve_pixel_3;
XeResolveLoad4RGBAUnswappedPixelSamplesFromRaw(
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,
msaa_resolve_pixel_0, msaa_resolve_pixel_1, msaa_resolve_pixel_2,
msaa_resolve_pixel_3);
XeResolveDecodePWLGammaSource(resolve_info, msaa_resolve_pixel_0);
XeResolveDecodePWLGammaSource(resolve_info, msaa_resolve_pixel_1);
XeResolveDecodePWLGammaSource(resolve_info, msaa_resolve_pixel_2);
XeResolveDecodePWLGammaSource(resolve_info, msaa_resolve_pixel_3);
pixel_0 += msaa_resolve_pixel_0;
pixel_1 += msaa_resolve_pixel_1;
pixel_2 += msaa_resolve_pixel_2;
pixel_3 += msaa_resolve_pixel_3;
dont_flatten_xe
if (resolve_info.sample_select >= kXenosCopySampleSelect_0123) {
uint sample_stride_bytes = 4u << resolve_info.edram_format_ints_log2;
exp_bias *= 0.5f;
XeResolveLoad4RGBAUnswappedPixelSamplesFromRaw(
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,
msaa_resolve_pixel_0, msaa_resolve_pixel_1, msaa_resolve_pixel_2,
msaa_resolve_pixel_3);
XeResolveDecodePWLGammaSource(resolve_info, msaa_resolve_pixel_0);
XeResolveDecodePWLGammaSource(resolve_info, msaa_resolve_pixel_1);
XeResolveDecodePWLGammaSource(resolve_info, msaa_resolve_pixel_2);
XeResolveDecodePWLGammaSource(resolve_info, msaa_resolve_pixel_3);
pixel_0 += msaa_resolve_pixel_0;
pixel_1 += msaa_resolve_pixel_1;
pixel_2 += msaa_resolve_pixel_2;
pixel_3 += msaa_resolve_pixel_3;
XeResolveLoad4RGBAUnswappedPixelSamplesFromRaw(
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, msaa_resolve_pixel_0,
msaa_resolve_pixel_1, msaa_resolve_pixel_2, msaa_resolve_pixel_3);
XeResolveDecodePWLGammaSource(resolve_info, msaa_resolve_pixel_0);
XeResolveDecodePWLGammaSource(resolve_info, msaa_resolve_pixel_1);
XeResolveDecodePWLGammaSource(resolve_info, msaa_resolve_pixel_2);
XeResolveDecodePWLGammaSource(resolve_info, msaa_resolve_pixel_3);
pixel_0 += msaa_resolve_pixel_0;
pixel_1 += msaa_resolve_pixel_1;
pixel_2 += msaa_resolve_pixel_2;
pixel_3 += msaa_resolve_pixel_3;
}
}
pixel_0 *= exp_bias;
pixel_1 *= exp_bias;
pixel_2 *= exp_bias;
pixel_3 *= exp_bias;
XeResolveEncodePWLGammaDest(resolve_info, pixel_0);
XeResolveEncodePWLGammaDest(resolve_info, pixel_1);
XeResolveEncodePWLGammaDest(resolve_info, pixel_2);
XeResolveEncodePWLGammaDest(resolve_info, pixel_3);
dont_flatten_xe if (resolve_info.dest_swap) {
pixel_0 = pixel_0.bgra;
pixel_1 = pixel_1.bgra;
pixel_2 = pixel_2.bgra;
pixel_3 = pixel_3.bgra;
}
}
void XeResolveLoad8RedColors(
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)) {
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.
address_bytes += 4u;
}
XeResolveLoad8RedPixelSamplesFromRaw(
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)) {
pixels_0123 = XePWLGammaToLinear4(pixels_0123);
pixels_4567 = XePWLGammaToLinear4(pixels_4567);
}
float exp_bias = resolve_info.dest_exp_bias_factor;
dont_flatten_xe
if (resolve_info.sample_select >= kXenosCopySampleSelect_01) {
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(
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,
msaa_resolve_pixels_4567);
dont_flatten_xe if (XeResolveSourceUsesPWLGamma(resolve_info)) {
msaa_resolve_pixels_0123 =
XePWLGammaToLinear4(msaa_resolve_pixels_0123);
msaa_resolve_pixels_4567 =
XePWLGammaToLinear4(msaa_resolve_pixels_4567);
}
pixels_0123 += msaa_resolve_pixels_0123;
pixels_4567 += msaa_resolve_pixels_4567;
dont_flatten_xe
if (resolve_info.sample_select >= kXenosCopySampleSelect_0123) {
uint sample_stride_bytes = 4u << resolve_info.edram_format_ints_log2;
exp_bias *= 0.5f;
XeResolveLoad8RedPixelSamplesFromRaw(
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,
msaa_resolve_pixels_4567);
dont_flatten_xe if (XeResolveSourceUsesPWLGamma(resolve_info)) {
msaa_resolve_pixels_0123 =
XePWLGammaToLinear4(msaa_resolve_pixels_0123);
msaa_resolve_pixels_4567 =
XePWLGammaToLinear4(msaa_resolve_pixels_4567);
}
pixels_0123 += msaa_resolve_pixels_0123;
pixels_4567 += msaa_resolve_pixels_4567;
XeResolveLoad8RedPixelSamplesFromRaw(
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,
msaa_resolve_pixels_0123, msaa_resolve_pixels_4567);
dont_flatten_xe if (XeResolveSourceUsesPWLGamma(resolve_info)) {
msaa_resolve_pixels_0123 =
XePWLGammaToLinear4(msaa_resolve_pixels_0123);
msaa_resolve_pixels_4567 =
XePWLGammaToLinear4(msaa_resolve_pixels_4567);
}
pixels_0123 += msaa_resolve_pixels_0123;
pixels_4567 += msaa_resolve_pixels_4567;
}
}
pixels_0123 *= exp_bias;
pixels_4567 *= exp_bias;
}
#endif // XE_RESOLVE_COPY_EDRAM_BYTE_BUFFER_ALIGNMENT == 4
uint4_xe XeResolveSwapRedBlue_8_8_8_8(uint4_xe pixels) {
return (pixels & ~0xFF00FFu) | ((pixels & 0xFFu) << 16u) |
((pixels >> 16u) & 0xFFu);
}
uint4_xe XeResolveSwapRedBlue_2_10_10_10(uint4_xe pixels) {
return (pixels & ~0x3FF003FF) | ((pixels & 0x3FFu) << 20u) |
((pixels >> 20u) & 0x3FFu);
}
void XeResolveSwap8PixelsRedBlue32bpp(
XeResolveInfo resolve_info, inout_param_xe(uint4_xe, pixels_0123),
inout_param_xe(uint4_xe, pixels_4567)) {
dont_flatten_xe if (resolve_info.dest_swap) {
switch (resolve_info.edram_format) {
case kXenosColorRenderTargetFormat_8_8_8_8:
case kXenosColorRenderTargetFormat_8_8_8_8_GAMMA:
pixels_0123 = XeResolveSwapRedBlue_8_8_8_8(pixels_0123);
pixels_4567 = XeResolveSwapRedBlue_8_8_8_8(pixels_4567);
break;
case kXenosColorRenderTargetFormat_2_10_10_10:
case kXenosColorRenderTargetFormat_2_10_10_10_FLOAT:
case kXenosColorRenderTargetFormat_2_10_10_10_AS_10_10_10_10:
case kXenosColorRenderTargetFormat_2_10_10_10_FLOAT_AS_16_16_16_16:
pixels_0123 = XeResolveSwapRedBlue_2_10_10_10(pixels_0123);
pixels_4567 = XeResolveSwapRedBlue_2_10_10_10(pixels_4567);
break;
}
}
}
void XeResolveSwap4PixelsRedBlue64bpp(
XeResolveInfo resolve_info, inout_param_xe(uint4_xe, pixels_01),
inout_param_xe(uint4_xe, pixels_23)) {
dont_flatten_xe if (resolve_info.dest_swap) {
dont_flatten_xe
if (resolve_info.edram_format ==
kXenosColorRenderTargetFormat_16_16_16_16 ||
resolve_info.edram_format ==
kXenosColorRenderTargetFormat_16_16_16_16_FLOAT) {
pixels_01 = (pixels_01 & ~0xFFFFu) | (pixels_01.yxwz & 0xFFFFu);
pixels_23 = (pixels_23 & ~0xFFFFu) | (pixels_23.yxwz & 0xFFFFu);
}
}
}
#endif
#endif // XENIA_GPU_SHADERS_RESOLVE_XESLI_