151 lines
6.6 KiB
HLSL
151 lines
6.6 KiB
HLSL
#include "byte_swap.hlsli"
|
|
#include "edram_load_store.hlsli"
|
|
#include "texture_address.hlsli"
|
|
|
|
[numthreads(20, 16, 1)]
|
|
void main(uint3 xe_group_id : SV_GroupID,
|
|
uint3 xe_group_thread_id : SV_GroupThreadID,
|
|
uint3 xe_thread_id : SV_DispatchThreadID) {
|
|
// 1 group = 80x16 destination (with resolution scale applied) pixels.
|
|
// 1 thread = 4 destination pixels.
|
|
|
|
uint4 sample_count_and_scale_info = XeEDRAMSampleCountAndScaleInfo();
|
|
|
|
// Check if the whole thread is not out of the rectangle's Y bounds, and if X
|
|
// coordinates in the thread are inside the rectangle's X bounds.
|
|
uint2 dispatch_pixel_index_unscaled =
|
|
(xe_thread_id.xy >> sample_count_and_scale_info.z) * uint2(4u, 1u);
|
|
uint2 source_rect_unscaled_tl = xe_edram_tile_sample_dimensions >> 17u;
|
|
uint2 source_rect_unscaled_br =
|
|
source_rect_unscaled_tl + (xe_edram_tile_sample_dimensions & 0xFFFu);
|
|
uint4 dispatch_pixel_x_coords_unscaled =
|
|
dispatch_pixel_index_unscaled.x + uint4(0u, 1u, 2u, 3u);
|
|
bool4 x_in_rect =
|
|
dispatch_pixel_x_coords_unscaled >= source_rect_unscaled_tl.x &&
|
|
dispatch_pixel_x_coords_unscaled < source_rect_unscaled_br.x;
|
|
[branch] if (dispatch_pixel_index_unscaled.y < source_rect_unscaled_tl.y ||
|
|
dispatch_pixel_index_unscaled.y >= source_rect_unscaled_br.y ||
|
|
!any(x_in_rect)) {
|
|
return;
|
|
}
|
|
|
|
uint2 texel_sub_index_scaled =
|
|
xe_group_thread_id.xy & sample_count_and_scale_info.z;
|
|
|
|
// Calculate the EDRAM offset of the samples of the pixel.
|
|
// 1 group uses:
|
|
// - 1x resolution, 1x AA - 1x1 tile.
|
|
// - 1x resolution, 2x AA - 1x2 tiles
|
|
// (group thread ID Y < or >= 8 to choose the tile).
|
|
// - 1x resolution, 4x AA - 2x2 tiles
|
|
// (same, plus group thread ID X < or >= 10 to choose the tile).
|
|
// - 2x resolution, 1x AA - 0.5x0.5 tiles
|
|
// (group ID & 1 to choose the quarter of the tile).
|
|
// - 2x resolution, 2x AA - 0.5x1 tiles
|
|
// (group ID X & 1 to choose the X half of the tile).
|
|
// - 2x resolution, 4x AA - 1x1 tile.
|
|
uint2 edram_tile_index, edram_tile_sample_index;
|
|
[branch] if (sample_count_and_scale_info.z != 0u) {
|
|
edram_tile_index = xe_group_id.xy >> (sample_count_and_scale_info.xy ^ 1u);
|
|
edram_tile_sample_index =
|
|
((xe_group_id.xy & 1u) >> sample_count_and_scale_info.xy) *
|
|
uint2(40u, 8u) +
|
|
(xe_group_thread_id.xy >> 1u <<
|
|
(sample_count_and_scale_info.xy + uint2(2u, 0u)));
|
|
} else {
|
|
uint2 edram_multisample_tile =
|
|
uint2(uint2(10u, 8u) <= xe_group_thread_id.xy) *
|
|
sample_count_and_scale_info.xy;
|
|
edram_tile_index =
|
|
(xe_group_id.xy << sample_count_and_scale_info.xy) +
|
|
edram_multisample_tile;
|
|
edram_tile_sample_index =
|
|
((xe_group_thread_id.xy - edram_multisample_tile * uint2(10u, 8u)) <<
|
|
(sample_count_and_scale_info.xy + uint2(2u, 0u)));
|
|
}
|
|
edram_tile_sample_index +=
|
|
(xe_edram_tile_sample_dest_info.xx >> uint2(15u, 14u)) & 1u;
|
|
// Force use the lower host texel for the topmost guest texel row to reduce
|
|
// the impact of half-pixel offset.
|
|
uint2 edram_texel_sub_index = texel_sub_index_scaled;
|
|
if (sample_count_and_scale_info.w != 0u) {
|
|
edram_texel_sub_index.y |=
|
|
uint(dispatch_pixel_index_unscaled.y == source_rect_unscaled_tl.y);
|
|
}
|
|
uint4 edram_offsets;
|
|
edram_offsets.x = XeEDRAMOffset32bpp(edram_tile_index,
|
|
edram_tile_sample_index,
|
|
edram_texel_sub_index);
|
|
// Read pixels from the EDRAM buffer.
|
|
uint4 pixels;
|
|
[branch] if (sample_count_and_scale_info.z != 0u) {
|
|
// 4 host pixels within each sample, thus guest pixels are each 4 dwords
|
|
// away from each other at 1x/2x AA and 8 dwords away at 4x AA.
|
|
edram_offsets.yzw =
|
|
(uint3(16u, 32u, 48u) << sample_count_and_scale_info.x) +
|
|
edram_offsets.x;
|
|
if (sample_count_and_scale_info.w != 0u) {
|
|
// Force use the right host texel for the leftmost guest texel column to
|
|
// reduce the impact of half-pixel offset.
|
|
edram_offsets |=
|
|
(dispatch_pixel_x_coords_unscaled == source_rect_unscaled_tl.x) ? 4u
|
|
: 0u;
|
|
}
|
|
pixels.x = xe_edram_load_store_source.Load(edram_offsets.x);
|
|
pixels.y = xe_edram_load_store_source.Load(edram_offsets.y);
|
|
pixels.z = xe_edram_load_store_source.Load(edram_offsets.z);
|
|
pixels.w = xe_edram_load_store_source.Load(edram_offsets.w);
|
|
} else {
|
|
// At 1x and 2x, this contains samples of 4 pixels. At 4x, this contains
|
|
// samples of 2, need to load 2 more.
|
|
[branch] if (sample_count_and_scale_info.x != 0u) {
|
|
edram_offsets.yzw = uint3(8u, 16u, 24u) + edram_offsets.x;
|
|
pixels.x = xe_edram_load_store_source.Load(edram_offsets.x);
|
|
pixels.y = xe_edram_load_store_source.Load(edram_offsets.y);
|
|
pixels.z = xe_edram_load_store_source.Load(edram_offsets.z);
|
|
pixels.w = xe_edram_load_store_source.Load(edram_offsets.w);
|
|
} else {
|
|
pixels = xe_edram_load_store_source.Load4(edram_offsets.x);
|
|
}
|
|
}
|
|
|
|
// Swap blue and red if needed.
|
|
uint red_blue_swap = xe_edram_tile_sample_dest_info >> 19u;
|
|
if (red_blue_swap != 0u) {
|
|
uint red_mask = (1u << (red_blue_swap & 31u)) - 1u;
|
|
// No need to be ready for a long shift Barney, it's just 16 or 20.
|
|
uint blue_shift = red_blue_swap >> 5u;
|
|
uint blue_mask = red_mask << blue_shift;
|
|
pixels = (pixels & ~(red_mask | blue_mask)) |
|
|
((pixels & red_mask) << blue_shift) |
|
|
((pixels >> blue_shift) & red_mask);
|
|
}
|
|
|
|
// Tile the pixels to the shared memory or to the scaled resolve memory.
|
|
pixels = XeByteSwap(pixels, xe_edram_tile_sample_dest_info >> 16u);
|
|
uint2 texel_offset_unscaled =
|
|
((xe_edram_tile_sample_dimensions >> 12u) & 31u) +
|
|
dispatch_pixel_index_unscaled - source_rect_unscaled_tl;
|
|
// If texel_offset_unscaled.x is negative (if the rectangle is not
|
|
// 4-pixel-aligned, for example), the result will be ignored anyway due to
|
|
// x_in_rect.
|
|
uint4 texel_addresses =
|
|
(xe_edram_tile_sample_dest_base + XeTextureTiledOffset2D(
|
|
texel_offset_unscaled, xe_edram_tile_sample_dest_info & 16383u, 2u))
|
|
<< (sample_count_and_scale_info.z * 2u);
|
|
texel_addresses +=
|
|
texel_sub_index_scaled.x * 4u + texel_sub_index_scaled.y * 8u;
|
|
[branch] if (x_in_rect.x) {
|
|
xe_edram_load_store_dest.Store(texel_addresses.x, pixels.x);
|
|
}
|
|
[branch] if (x_in_rect.y) {
|
|
xe_edram_load_store_dest.Store(texel_addresses.y, pixels.y);
|
|
}
|
|
[branch] if (x_in_rect.z) {
|
|
xe_edram_load_store_dest.Store(texel_addresses.z, pixels.z);
|
|
}
|
|
[branch] if (x_in_rect.w) {
|
|
xe_edram_load_store_dest.Store(texel_addresses.w, pixels.w);
|
|
}
|
|
}
|