[DXBC] New tfetch: pre-swizzle signs, additive LOD + refactoring

This commit is contained in:
Triang3l
2020-06-06 19:12:34 +03:00
parent 68dd818029
commit 8a64861ec0
43 changed files with 4018 additions and 4903 deletions

View File

@@ -1279,10 +1279,9 @@ void TextureCache::RequestTextures(uint32_t used_texture_mask) {
const auto& fetch = regs.Get<xenos::xe_gpu_texture_fetch_t>(
XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0 + index * 6);
TextureKey old_key = binding.key;
bool old_has_unsigned = binding.has_unsigned;
bool old_has_signed = binding.has_signed;
BindingInfoFromFetchConstant(fetch, binding.key, &binding.swizzle,
&binding.has_unsigned, &binding.has_signed);
uint8_t old_swizzled_signs = binding.swizzled_signs;
BindingInfoFromFetchConstant(fetch, binding.key, &binding.host_swizzle,
&binding.swizzled_signs);
texture_keys_in_sync_ |= index_bit;
if (binding.key.IsInvalid()) {
binding.texture = nullptr;
@@ -1298,20 +1297,21 @@ void TextureCache::RequestTextures(uint32_t used_texture_mask) {
if (IsSignedVersionSeparate(binding.key.format)) {
// Can reuse previously loaded unsigned/signed versions if the key is the
// same and the texture was previously bound as unsigned/signed
// respectively (checking the previous values of has_unsigned/has_signed
// rather than binding.texture != nullptr and binding.texture_signed !=
// nullptr also prevents repeated attempts to load the texture if it has
// failed to load).
if (binding.has_unsigned) {
if (key_changed || !old_has_unsigned) {
// respectively (checking the previous values of signedness rather than
// binding.texture != nullptr and binding.texture_signed != nullptr also
// prevents repeated attempts to load the texture if it has failed to
// load).
if (texture_util::IsAnySignNotSigned(binding.swizzled_signs)) {
if (key_changed ||
!texture_util::IsAnySignNotSigned(old_swizzled_signs)) {
binding.texture = FindOrCreateTexture(binding.key);
load_unsigned_data = true;
}
} else {
binding.texture = nullptr;
}
if (binding.has_signed) {
if (key_changed || !old_has_signed) {
if (texture_util::IsAnySignSigned(binding.swizzled_signs)) {
if (key_changed || !texture_util::IsAnySignSigned(old_swizzled_signs)) {
TextureKey signed_key = binding.key;
signed_key.signed_separate = 1;
binding.texture_signed = FindOrCreateTexture(signed_key);
@@ -1380,15 +1380,13 @@ uint64_t TextureCache::GetDescriptorHashForActiveTextures(
sizeof(texture_srv.dimension));
XXH64_update(&hash_state, &texture_srv.is_signed,
sizeof(texture_srv.is_signed));
XXH64_update(&hash_state, &texture_srv.is_sign_required,
sizeof(texture_srv.is_sign_required));
const TextureBinding& binding =
texture_bindings_[texture_srv.fetch_constant];
XXH64_update(&hash_state, &binding.key, sizeof(binding.key));
XXH64_update(&hash_state, &binding.swizzle, sizeof(binding.swizzle));
XXH64_update(&hash_state, &binding.has_unsigned,
sizeof(binding.has_unsigned));
XXH64_update(&hash_state, &binding.has_signed, sizeof(binding.has_signed));
XXH64_update(&hash_state, &binding.host_swizzle,
sizeof(binding.host_swizzle));
XXH64_update(&hash_state, &binding.swizzled_signs,
sizeof(binding.swizzled_signs));
}
return XXH64_digest(&hash_state);
}
@@ -1418,7 +1416,7 @@ void TextureCache::WriteTextureSRV(const D3D12Shader::TextureSRV& texture_srv,
if (texture_srv.is_signed) {
// Not supporting signed compressed textures - hopefully DXN and DXT5A are
// not used as signed.
if (binding.has_signed || texture_srv.is_sign_required) {
if (texture_util::IsAnySignSigned(binding.swizzled_signs)) {
desc.Format = host_formats_[uint32_t(format)].dxgi_format_snorm;
if (desc.Format == DXGI_FORMAT_UNKNOWN) {
unsupported_format_features_used_[uint32_t(format)] |=
@@ -1426,7 +1424,7 @@ void TextureCache::WriteTextureSRV(const D3D12Shader::TextureSRV& texture_srv,
}
}
} else {
if (binding.has_unsigned || texture_srv.is_sign_required) {
if (texture_util::IsAnySignNotSigned(binding.swizzled_signs)) {
desc.Format = GetDXGIUnormFormat(binding.key);
if (desc.Format == DXGI_FORMAT_UNKNOWN) {
unsupported_format_features_used_[uint32_t(format)] |=
@@ -1441,7 +1439,7 @@ void TextureCache::WriteTextureSRV(const D3D12Shader::TextureSRV& texture_srv,
// XE_GPU_SWIZZLE and D3D12_SHADER_COMPONENT_MAPPING are the same except for
// one bit.
desc.Shader4ComponentMapping =
binding.swizzle |
binding.host_swizzle |
D3D12_SHADER_COMPONENT_MAPPING_ALWAYS_SET_BIT_AVOIDING_ZEROMEM_MISTAKES;
} else {
binding_dimension = Dimension::k2D;
@@ -1522,7 +1520,7 @@ void TextureCache::WriteTextureSRV(const D3D12Shader::TextureSRV& texture_srv,
if (texture->cached_srv_descriptor_swizzle !=
Texture::kCachedSRVDescriptorSwizzleMissing) {
// Use an existing cached descriptor if it has the needed swizzle.
if (binding.swizzle == texture->cached_srv_descriptor_swizzle) {
if (binding.host_swizzle == texture->cached_srv_descriptor_swizzle) {
cached_handle_available = true;
cached_handle = texture->cached_srv_descriptor;
}
@@ -1561,7 +1559,7 @@ void TextureCache::WriteTextureSRV(const D3D12Shader::TextureSRV& texture_srv,
if (cached_handle_available) {
device->CreateShaderResourceView(resource, &desc, cached_handle);
texture->cached_srv_descriptor = cached_handle;
texture->cached_srv_descriptor_swizzle = binding.swizzle;
texture->cached_srv_descriptor_swizzle = binding.host_swizzle;
}
}
if (cached_handle_available) {
@@ -1591,7 +1589,6 @@ TextureCache::SamplerParameters TextureCache::GetSamplerParameters(
&mip_max_level, binding.mip_filter);
parameters.mip_min_level = mip_min_level;
parameters.mip_max_level = std::max(mip_max_level, mip_min_level);
parameters.lod_bias = fetch.lod_bias;
AnisoFilter aniso_filter = binding.aniso_filter == AnisoFilter::kUseFetchConst
? fetch.aniso_filter
@@ -1662,7 +1659,8 @@ void TextureCache::WriteSampler(SamplerParameters parameters,
desc.AddressU = kAddressModeMap[uint32_t(parameters.clamp_x)];
desc.AddressV = kAddressModeMap[uint32_t(parameters.clamp_y)];
desc.AddressW = kAddressModeMap[uint32_t(parameters.clamp_z)];
desc.MipLODBias = parameters.lod_bias * (1.0f / 32.0f);
// LOD is calculated in shaders.
desc.MipLODBias = 0.0f;
desc.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER;
// TODO(Triang3l): Border colors k_ACBYCR_BLACK and k_ACBCRY_BLACK.
if (parameters.border_color == BorderColor::k_AGBR_White) {
@@ -2018,7 +2016,7 @@ ID3D12Resource* TextureCache::RequestSwapTexture(
XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0);
TextureKey key;
uint32_t swizzle;
BindingInfoFromFetchConstant(fetch, key, &swizzle, nullptr, nullptr);
BindingInfoFromFetchConstant(fetch, key, &swizzle, nullptr);
if (key.base_page == 0 || key.dimension != Dimension::k2D) {
return nullptr;
}
@@ -2072,19 +2070,16 @@ TextureCache::LoadMode TextureCache::GetLoadMode(TextureKey key) {
void TextureCache::BindingInfoFromFetchConstant(
const xenos::xe_gpu_texture_fetch_t& fetch, TextureKey& key_out,
uint32_t* swizzle_out, bool* has_unsigned_out, bool* has_signed_out) {
uint32_t* host_swizzle_out, uint8_t* swizzled_signs_out) {
// Reset the key and the swizzle.
key_out.MakeInvalid();
if (swizzle_out != nullptr) {
*swizzle_out = xenos::XE_GPU_SWIZZLE_0 | (xenos::XE_GPU_SWIZZLE_0 << 3) |
(xenos::XE_GPU_SWIZZLE_0 << 6) |
(xenos::XE_GPU_SWIZZLE_0 << 9);
if (host_swizzle_out != nullptr) {
*host_swizzle_out =
xenos::XE_GPU_SWIZZLE_0 | (xenos::XE_GPU_SWIZZLE_0 << 3) |
(xenos::XE_GPU_SWIZZLE_0 << 6) | (xenos::XE_GPU_SWIZZLE_0 << 9);
}
if (has_unsigned_out != nullptr) {
*has_unsigned_out = false;
}
if (has_signed_out != nullptr) {
*has_signed_out = false;
if (swizzled_signs_out != nullptr) {
*swizzled_signs_out = uint8_t(TextureSign::kUnsigned) * uint8_t(0b01010101);
}
switch (fetch.type) {
@@ -2096,8 +2091,7 @@ void TextureCache::BindingInfoFromFetchConstant(
}
XELOGW(
"Texture fetch constant ({:08X} {:08X} {:08X} {:08X} {:08X} {:08X}) "
"has "
"\"invalid\" type! This is incorrect behavior, but you can try "
"has \"invalid\" type! This is incorrect behavior, but you can try "
"bypassing this by launching Xenia with "
"--gpu_allow_invalid_fetch_constants=true.",
fetch.dword_0, fetch.dword_1, fetch.dword_2, fetch.dword_3,
@@ -2106,8 +2100,7 @@ void TextureCache::BindingInfoFromFetchConstant(
default:
XELOGW(
"Texture fetch constant ({:08X} {:08X} {:08X} {:08X} {:08X} {:08X}) "
"is "
"completely invalid!",
"is completely invalid!",
fetch.dword_0, fetch.dword_1, fetch.dword_2, fetch.dword_3,
fetch.dword_4, fetch.dword_5);
return;
@@ -2144,36 +2137,26 @@ void TextureCache::BindingInfoFromFetchConstant(
key_out.format = format;
key_out.endianness = fetch.endianness;
if (swizzle_out != nullptr) {
uint32_t swizzle = 0;
if (host_swizzle_out != nullptr) {
uint32_t host_swizzle = 0;
for (uint32_t i = 0; i < 4; ++i) {
uint32_t swizzle_component = (fetch.swizzle >> (i * 3)) & 0b111;
if (swizzle_component >= 4) {
uint32_t host_swizzle_component = (fetch.swizzle >> (i * 3)) & 0b111;
if (host_swizzle_component >= 4) {
// Get rid of 6 and 7 values (to prevent device losses if the game has
// something broken) the quick and dirty way - by changing them to 4 (0)
// and 5 (1).
swizzle_component &= 0b101;
host_swizzle_component &= 0b101;
} else {
swizzle_component =
host_formats_[uint32_t(format)].swizzle[swizzle_component];
host_swizzle_component =
host_formats_[uint32_t(format)].swizzle[host_swizzle_component];
}
swizzle |= swizzle_component << (i * 3);
host_swizzle |= host_swizzle_component << (i * 3);
}
*swizzle_out = swizzle;
*host_swizzle_out = host_swizzle;
}
// TODO(Triang3l): Move to texture_util::SwizzleSigns.
if (has_unsigned_out != nullptr) {
*has_unsigned_out = fetch.sign_x != TextureSign::kSigned ||
fetch.sign_y != TextureSign::kSigned ||
fetch.sign_z != TextureSign::kSigned ||
fetch.sign_w != TextureSign::kSigned;
}
if (has_signed_out != nullptr) {
*has_signed_out = fetch.sign_x == TextureSign::kSigned ||
fetch.sign_y == TextureSign::kSigned ||
fetch.sign_z == TextureSign::kSigned ||
fetch.sign_w == TextureSign::kSigned;
if (swizzled_signs_out != nullptr) {
*swizzled_signs_out = texture_util::SwizzleSigns(fetch);
}
}