[D3D12] Experimental 2x resolution scale

This commit is contained in:
Triang3l
2018-12-06 10:19:07 +03:00
parent 132af3e266
commit 9427667a27
173 changed files with 16680 additions and 4985 deletions

View File

@@ -6,37 +6,111 @@
void main(uint3 xe_group_id : SV_GroupID,
uint3 xe_group_thread_id : SV_GroupThreadID,
uint3 xe_thread_id : SV_DispatchThreadID) {
// Check if not outside of the destination texture completely.
uint2 source_offset = xe_edram_tile_sample_dimensions >> 17u;
[branch] if (any(xe_thread_id.xy * uint2(4u, 1u) < source_offset.xy)) {
return;
}
uint2 texel_index = xe_thread_id.xy - source_offset;
texel_index.x *= 4u;
uint2 copy_size = xe_edram_tile_sample_dimensions & 0xFFFu;
[branch] if (any(texel_index >= copy_size)) {
// 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;
}
// Get the samples from the EDRAM buffer.
// XY - log2(pixel size), ZW - selected sample offset.
uint4 sample_info =
(xe_edram_tile_sample_dest_info.xxxx >> uint4(15u, 14u, 17u, 16u)) & 1u;
uint2 edram_tile_quarter =
uint2(uint2(10u, 8u) <= xe_group_thread_id.xy) * sample_info.xy;
uint edram_offset = XeEDRAMOffset32bpp(
(xe_group_id.xy << sample_info.xy) + edram_tile_quarter,
((xe_group_thread_id.xy - edram_tile_quarter * uint2(10u, 8u)) <<
(sample_info.xy + uint2(2u, 0u))) + sample_info.zw);
// At 1x and 2x, this contains samples of 4 pixels. At 4x, this contains
// samples of 2, need to load 2 more.
uint4 pixels = xe_edram_load_store_source.Load4(edram_offset);
[branch] if (sample_info.x != 0u) {
pixels.xy = pixels.xz;
pixels.zw = xe_edram_load_store_source.Load3(edram_offset + 16u).xz;
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);
}
}
uint red_blue_swap = xe_edram_tile_sample_dest_info >> 21u;
// 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.
@@ -47,22 +121,30 @@ void main(uint3 xe_group_id : SV_GroupID,
((pixels >> blue_shift) & red_mask);
}
// Tile the pixels to the shared memory.
pixels = XeByteSwap(pixels, xe_edram_tile_sample_dest_info >> 18u);
// 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(
((xe_edram_tile_sample_dimensions >> 12u) & 31u) + texel_index,
xe_edram_tile_sample_dest_info & 16383u, 2u);
xe_edram_load_store_dest.Store(texel_addresses.x, pixels.x);
bool3 texels_in_rect = uint3(1u, 2u, 3u) + texel_index.x < copy_size.x;
[branch] if (texels_in_rect.x) {
(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 (texels_in_rect.y) {
xe_edram_load_store_dest.Store(texel_addresses.z, pixels.z);
[branch] if (texels_in_rect.z) {
xe_edram_load_store_dest.Store(texel_addresses.w, pixels.w);
}
}
}
[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);
}
}