[D3D12] EDRAM storing and random cleanup

This commit is contained in:
Triang3l
2018-08-11 20:33:33 +03:00
parent a4b98cda31
commit 9b303c64ba
17 changed files with 760 additions and 11 deletions

View File

@@ -0,0 +1,14 @@
#include "edram_load_store.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) {
uint2 tile_dword_index = xe_group_thread_id.xy;
tile_dword_index.x *= 4u;
uint4 pixels = xe_edram_load_store_source.Load4(
XeEDRAMOffset(xe_group_id.xy, tile_dword_index));
uint rt_offset = xe_thread_id.y * xe_edram_rt_color_depth_pitch +
xe_thread_id.x * 16u;
xe_edram_load_store_dest.Store4(rt_offset, pixels);
}

View File

@@ -0,0 +1,19 @@
#include "edram_load_store.hlsli"
[numthreads(40, 8, 1)]
void main(uint3 xe_group_id : SV_GroupID,
uint3 xe_group_thread_id : SV_GroupThreadID,
uint3 xe_thread_id : SV_DispatchThreadID) {
// One tile contains 80x8 texels, and 2 rows within a 80x16 tile contain data
// from 1 render target row rather than 1. Threads with X 0-19 are for the
// first row, with 20-39 are for the second.
uint2 tile_dword_index = xe_group_thread_id.xy * uint2(4u, 2u);
[flatten] if (xe_group_thread_id.x >= 20u) {
tile_dword_index += uint2(uint(-80), 1u);
}
uint4 pixels = xe_edram_load_store_source.Load4(
XeEDRAMOffset(xe_group_id.xy, tile_dword_index));
uint rt_offset = xe_thread_id.y * xe_edram_rt_color_depth_pitch +
xe_thread_id.x * 16u;
xe_edram_load_store_dest.Store4(rt_offset, pixels);
}

View File

@@ -0,0 +1,20 @@
#include "edram_load_store.hlsli"
#include "pixel_formats.hlsli"
[numthreads(40, 16, 1)]
void main(uint3 xe_group_id : SV_GroupID,
uint3 xe_group_thread_id : SV_GroupThreadID,
uint3 xe_thread_id : SV_DispatchThreadID) {
uint2 tile_dword_index = xe_group_thread_id.xy;
tile_dword_index.x *= 2u;
uint2 pixels_7e3_packed = xe_edram_load_store_source.Load2(
XeEDRAMOffset(xe_group_id.xy, tile_dword_index));
uint4 pixel_0_f16u32 = XeFloat7e3To16(pixels_7e3_packed.x);
uint4 pixel_1_f16u32 = XeFloat7e3To16(pixels_7e3_packed.y);
uint4 pixels_f16u32_packed =
uint4(pixel_0_f16u32.xz, pixel_1_f16u32.xz) |
(uint4(pixel_0_f16u32.yw, pixel_1_f16u32.yw) << 16u);
uint rt_offset = xe_thread_id.y * xe_edram_rt_color_depth_pitch +
xe_thread_id.x * 16u;
xe_edram_load_store_dest.Store4(rt_offset, pixels_f16u32_packed);
}

View File

@@ -0,0 +1,31 @@
#include "edram_load_store.hlsli"
#include "pixel_formats.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) {
uint2 tile_dword_index = xe_group_thread_id.xy;
tile_dword_index.x *= 4u;
uint edram_offset = XeEDRAMOffset(xe_group_id.xy, tile_dword_index);
uint4 depth24_stencil = xe_edram_load_store_source.Load4(edram_offset);
uint4 depth24 = depth24_stencil & 0xFFFFFFu;
uint4 depth32 = xe_edram_load_store_source.Load4(10485760u + edram_offset);
// Depth. If the stored 32-bit depth converted to 24-bit is the same as the
// stored 24-bit depth, load the 32-bit value because it has more precision
// (and multipass rendering is possible), if it's not, convert the 24-bit
// depth because it was overwritten by aliasing.
uint4 depth24to32 = XeFloat20e4To32(depth24);
uint4 depth = depth24to32 + (depth32 - depth24to32) *
uint4(XeFloat32To20e4(depth32) == depth24);
uint rt_offset = xe_thread_id.y * xe_edram_rt_color_depth_pitch +
xe_thread_id.x * 16u;
xe_edram_load_store_dest.Store4(rt_offset, depth);
// Stencil.
uint4 stencil = (depth24_stencil >> 24u) << uint4(0u, 8u, 16u, 24u);
stencil.xy |= stencil.zw;
stencil.x |= stencil.y;
rt_offset = xe_edram_rt_stencil_offset +
xe_thread_id.y * xe_edram_rt_stencil_pitch + xe_thread_id.x * 4u;
xe_edram_load_store_dest.Store(rt_offset, stencil.x);
}

View File

@@ -0,0 +1,22 @@
#include "edram_load_store.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) {
uint2 tile_dword_index = xe_group_thread_id.xy;
tile_dword_index.x *= 4u;
uint4 pixels = xe_edram_load_store_source.Load4(
XeEDRAMOffset(xe_group_id.xy, tile_dword_index));
// Depth.
uint rt_offset = xe_thread_id.y * xe_edram_rt_color_depth_pitch +
xe_thread_id.x * 16u;
xe_edram_load_store_dest.Store4(rt_offset, pixels & 0xFFFFFFu);
// Stencil.
uint4 stencil = (pixels >> 24u) << uint4(0u, 8u, 16u, 24u);
stencil.xy |= stencil.zw;
stencil.x |= stencil.y;
rt_offset = xe_edram_rt_stencil_offset +
xe_thread_id.y * xe_edram_rt_stencil_pitch + xe_thread_id.x * 4u;
xe_edram_load_store_dest.Store(rt_offset, stencil.x);
}

View File

@@ -0,0 +1,21 @@
#ifndef XENIA_GPU_D3D12_SHADERS_EDRAM_LOAD_STORE_HLSLI_
#define XENIA_GPU_D3D12_SHADERS_EDRAM_LOAD_STORE_HLSLI_
cbuffer XeEDRAMLoadStoreConstants : register(b0) {
uint xe_edram_base_tiles;
uint xe_edram_pitch_tiles;
uint xe_edram_rt_color_depth_pitch;
uint xe_edram_rt_stencil_offset;
uint xe_edram_rt_stencil_pitch;
};
ByteAddressBuffer xe_edram_load_store_source : register(t0);
RWByteAddressBuffer xe_edram_load_store_dest : register(u0);
uint XeEDRAMOffset(uint2 tile_index, uint2 tile_dword_index) {
return (xe_edram_base_tiles + (tile_index.y * xe_edram_pitch_tiles) +
tile_index.x) * 5120u + tile_dword_index.y * 320u +
tile_dword_index.x * 4u;
}
#endif // XENIA_GPU_D3D12_SHADERS_EDRAM_LOAD_STORE_HLSLI_

View File

@@ -0,0 +1,14 @@
#include "edram_load_store.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) {
uint rt_offset = xe_thread_id.y * xe_edram_rt_color_depth_pitch +
xe_thread_id.x * 16u;
uint4 pixels = xe_edram_load_store_source.Load4(rt_offset);
uint2 tile_dword_index = xe_group_thread_id.xy;
tile_dword_index.x *= 4u;
xe_edram_load_store_dest.Store4(
XeEDRAMOffset(xe_group_id.xy, tile_dword_index), pixels);
}

View File

@@ -0,0 +1,19 @@
#include "edram_load_store.hlsli"
[numthreads(40, 8, 1)]
void main(uint3 xe_group_id : SV_GroupID,
uint3 xe_group_thread_id : SV_GroupThreadID,
uint3 xe_thread_id : SV_DispatchThreadID) {
uint rt_offset = xe_thread_id.y * xe_edram_rt_color_depth_pitch +
xe_thread_id.x * 16u;
uint4 pixels = xe_edram_load_store_source.Load4(rt_offset);
// One tile contains 80x8 texels, and 2 rows within a 80x16 tile contain data
// from 1 render target row rather than 1. Threads with X 0-19 are for the
// first row, with 20-39 are for the second.
uint2 tile_dword_index = xe_group_thread_id.xy * uint2(4u, 2u);
[flatten] if (xe_group_thread_id.x >= 20u) {
tile_dword_index += uint2(uint(-80), 1u);
}
xe_edram_load_store_dest.Store4(
XeEDRAMOffset(xe_group_id.xy, tile_dword_index), pixels);
}

View File

@@ -0,0 +1,19 @@
#include "edram_load_store.hlsli"
#include "pixel_formats.hlsli"
[numthreads(40, 16, 1)]
void main(uint3 xe_group_id : SV_GroupID,
uint3 xe_group_thread_id : SV_GroupThreadID,
uint3 xe_thread_id : SV_DispatchThreadID) {
uint rt_offset = xe_thread_id.y * xe_edram_rt_color_depth_pitch +
xe_thread_id.x * 16u;
uint4 pixels_f16u32_packed = xe_edram_load_store_source.Load4(rt_offset);
uint4 pixel_0_f16u32 = pixels_f16u32_packed.xxyy >> uint4(0u, 16u, 0u, 16u);
uint4 pixel_1_f16u32 = pixels_f16u32_packed.zzww >> uint4(0u, 16u, 0u, 16u);
uint2 pixels_7e3_packed =
uint2(XeFloat16To7e3(pixel_0_f16u32), XeFloat16To7e3(pixel_1_f16u32));
uint2 tile_dword_index = xe_group_thread_id.xy;
tile_dword_index.x *= 2u;
xe_edram_load_store_dest.Store2(
XeEDRAMOffset(xe_group_id.xy, tile_dword_index), pixels_7e3_packed);
}

View File

@@ -0,0 +1,25 @@
#include "edram_load_store.hlsli"
#include "pixel_formats.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) {
// Depth.
uint rt_offset = xe_thread_id.y * xe_edram_rt_color_depth_pitch +
xe_thread_id.x * 16u;
uint4 depth32 = xe_edram_load_store_source.Load4(rt_offset);
uint4 depth24_stencil = XeFloat32To20e4(depth32);
// Stencil.
rt_offset = xe_edram_rt_stencil_offset +
xe_thread_id.y * xe_edram_rt_stencil_pitch + xe_thread_id.x * 4u;
depth24_stencil |= xe_edram_load_store_source.Load(rt_offset).xxxx >>
uint4(0u, 8u, 16u, 24u) << 24u;
uint2 tile_dword_index = xe_group_thread_id.xy;
tile_dword_index.x *= 4u;
uint edram_offset = XeEDRAMOffset(xe_group_id.xy, tile_dword_index);
// Store 24-bit depth for aliasing and checking if 32-bit depth is up to date.
xe_edram_load_store_dest.Store4(edram_offset, depth24_stencil);
// Store 32-bit depth so precision isn't lost when doing multipass rendering.
xe_edram_load_store_dest.Store4(10485760u + edram_offset, depth32);
}

View File

@@ -0,0 +1,20 @@
#include "edram_load_store.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) {
// Depth.
uint rt_offset = xe_thread_id.y * xe_edram_rt_color_depth_pitch +
xe_thread_id.x * 16u;
uint4 pixels = xe_edram_load_store_source.Load4(rt_offset) & 0xFFFFFFu;
// Stencil.
rt_offset = xe_edram_rt_stencil_offset +
xe_thread_id.y * xe_edram_rt_stencil_pitch + xe_thread_id.x * 4u;
pixels |= xe_edram_load_store_source.Load(rt_offset).xxxx >>
uint4(0u, 8u, 16u, 24u) << 24u;
uint2 tile_dword_index = xe_group_thread_id.xy;
tile_dword_index.x *= 4u;
xe_edram_load_store_dest.Store4(
XeEDRAMOffset(xe_group_id.xy, tile_dword_index), pixels);
}

View File

@@ -0,0 +1,74 @@
#ifndef XENIA_GPU_D3D12_SHADERS_PIXEL_FORMATS_HLSLI_
#define XENIA_GPU_D3D12_SHADERS_PIXEL_FORMATS_HLSLI_
// https://github.com/Microsoft/DirectXTex/blob/master/DirectXTex/DirectXTexConvert.cpp
uint XeFloat16To7e3(uint4 rgba_f16u32) {
float4 rgba_f32 = f16tof32(rgba_f16u32);
uint3 rgb_f32u32 = asuint(rgba_f32.xyz);
// Keep only positive (high bit set means negative for both float and int) and
// saturate to 31.875 (also dropping NaNs).
rgb_f32u32 = uint3(clamp(int3(rgb_f32u32), 0, 0x41FF0000));
uint3 normalized = rgb_f32u32 + 0xC2000000u;
uint3 denormalized = ((rgb_f32u32 & 0x7FFFFFu) | 0x800000u) >>
((125u).xxx - (rgb_f32u32 >> 23u));
uint3 rgb_f10u32 = normalized + (denormalized - normalized) *
uint3(rgb_f32u32 < 0x3E800000u);
rgb_f10u32 =
((rgb_f10u32 + 0x7FFFu + ((rgb_f10u32 >> 16u) & 1u)) >> 16u) & 0x3FFu;
return rgb_f10u32.r | (rgb_f10u32.g << 10u) | (rgb_f10u32.b << 20u) |
(uint(saturate(rgba_f32.a) * 3.0) << 30u);
}
uint4 XeFloat7e3To16(uint rgba_packed) {
uint3 rgb_f10u32 = (rgba_packed.xxx >> uint3(0u, 10u, 20u)) & 0x3FFu;
uint3 mantissa = rgb_f10u32 & 0x7Fu;
uint3 exponent = rgb_f10u32 >> 7u;
// Normalize the values for the denormalized components.
// Exponent = 1;
// do { Exponent--; Mantissa <<= 1; } while ((Mantissa & 0x80) == 0);
uint3 is_denormalized = uint3(exponent == 0u);
uint3 mantissa_lzcnt = (7u).xxx - firstbithigh(mantissa);
exponent += ((1u).xxx - mantissa_lzcnt - exponent) * is_denormalized;
mantissa +=
(((mantissa << mantissa_lzcnt) & 0x7Fu) - mantissa) * is_denormalized;
// Combine into 32-bit float bits and clear zeros.
uint3 rgb_f32u32 = (((exponent + 124u) << 23u) | (mantissa << 16u)) *
uint3(rgb_f10u32 != 0u);
return f32tof16(float4(asfloat(rgb_f32u32),
float(rgba_packed >> 30u) * (1.0 / 3.0)));
}
// Based on CFloat24 from d3dref9.dll and the 6e4 code from:
// https://github.com/Microsoft/DirectXTex/blob/master/DirectXTex/DirectXTexConvert.cpp
// 6e4 has a different exponent bias allowing [0,512) values, 20e4 allows [0,2).
// We also can't clamp the stored value to 1 as load->store->load must be exact.
uint4 XeFloat32To20e4(uint4 f32u32) {
// Keep only positive (high bit set means negative for both float and int) and
// saturate to the maximum representable value near 2 (also dropping NaNs).
f32u32 = uint4(clamp(int4(f32u32), 0, 0x3FFFFFF8));
uint4 normalized = f32u32 + 0xC8000000u;
uint4 denormalized =
((f32u32 & 0x7FFFFFu) | 0x800000u) >> ((113u).xxxx - (f32u32 >> 23u));
uint4 f24u32 =
normalized + (denormalized - normalized) * uint4(f32u32 < 0x38800000u);
return ((f24u32 + 3u + ((f24u32 >> 3u) & 1u)) >> 3u) & 0xFFFFFFu;
}
uint4 XeFloat20e4To32(uint4 f24u32) {
uint4 mantissa = f24u32 & 0xF00000u;
uint4 exponent = f24u32 >> 20u;
// Normalize the values for the denormalized components.
// Exponent = 1;
// do { Exponent--; Mantissa <<= 1; } while ((Mantissa & 0x100000) == 0);
uint4 is_denormalized = uint4(exponent == 0u);
uint4 mantissa_lzcnt = (20u).xxxx - firstbithigh(mantissa);
exponent += ((1u).xxxx - mantissa_lzcnt - exponent) * is_denormalized;
mantissa +=
(((mantissa << mantissa_lzcnt) & 0xFFFFFu) - mantissa) * is_denormalized;
// Combine into 32-bit float bits and clear zeros.
return (((exponent + 112u) << 23u) | (mantissa << 3u)) * uint4(f24u32 != 0u);
}
#endif // XENIA_GPU_D3D12_SHADERS_PIXEL_FORMATS_HLSLI_