Fix mipmapped GOB dimensions calculation

When calculating mip-level dimensions in terms of GOBs, they need to be divided by 2 while rounding upwards rather than downwards. This fixes corrupted textures and OOB access on lower mip levels across a substantial amount of titles, reducing arbitrary crashes as a result.
This commit is contained in:
PixelyIon 2023-01-30 21:05:58 +05:30 committed by Billy Laws
parent c9b055d0e3
commit df3b961d5d

View File

@ -42,10 +42,10 @@ namespace skyline::gpu::texture {
// Iterate over every level, adding the size of the current level to the total size // Iterate over every level, adding the size of the current level to the total size
totalSize += (GobWidth * gobsWidth) * (GobHeight * util::AlignUp(gobsHeight, gobBlockHeight)) * util::AlignUp(gobsDepth, gobBlockDepth); totalSize += (GobWidth * gobsWidth) * (GobHeight * util::AlignUp(gobsHeight, gobBlockHeight)) * util::AlignUp(gobsDepth, gobBlockDepth);
// Successively divide every dimension by 2 until the final level is reached // Successively divide every dimension by 2 until the final level is reached, the division is rounded up to contain the padding GOBs
gobsWidth = std::max(gobsWidth / 2, 1UL); gobsWidth = std::max(util::DivideCeil(gobsWidth, 2UL), 1UL);
gobsHeight = std::max(gobsHeight / 2, 1UL); gobsHeight = std::max(util::DivideCeil(gobsHeight, 2UL), 1UL);
gobsDepth = std::max(gobsDepth / 2, 1UL); gobsDepth = std::max(gobsDepth / 2, 1UL); // The GOB depth is the same as the depth dimension and needs to be rounded down during the division
gobBlockHeight = CalculateBlockGobs(gobBlockHeight, gobsHeight); gobBlockHeight = CalculateBlockGobs(gobBlockHeight, gobsHeight);
gobBlockDepth = CalculateBlockGobs(gobBlockDepth, gobsDepth); gobBlockDepth = CalculateBlockGobs(gobBlockDepth, gobsDepth);
@ -74,8 +74,8 @@ namespace skyline::gpu::texture {
gobBlockHeight, gobBlockDepth gobBlockHeight, gobBlockDepth
); );
gobsWidth = std::max(gobsWidth / 2, 1UL); gobsWidth = std::max(util::DivideCeil(gobsWidth, 2UL), 1UL);
gobsHeight = std::max(gobsHeight / 2, 1UL); gobsHeight = std::max(util::DivideCeil(gobsHeight, 2UL), 1UL);
dimensions.width = std::max(dimensions.width / 2, 1U); dimensions.width = std::max(dimensions.width / 2, 1U);
dimensions.height = std::max(dimensions.height / 2, 1U); dimensions.height = std::max(dimensions.height / 2, 1U);