xenia-project / xenia

Xbox 360 Emulator Research Project
https://xenia.jp
Other
8.1k stars 1.12k forks source link

tfetch LOD selection needs cleanup #1563

Closed Triang3l closed 4 years ago

Triang3l commented 4 years ago

The DXBC shader translator and the D3D12 texture cache need to be slightly reworked (likely as a part of the whole ENCODE_D3D10_SB → DxbcOp rewrite).

http://web.archive.org/web/20090514012026/http://msdn.microsoft.com/en-us/library/bb313957.aspx Two important things to take into account:

"Unless" in the first apparently implies that for UseRegisterGradients to work, UseComputedLOD is required too — the LOD is computed from gradients, but they can be either implicit or explicit. If UseComputedLOD is false, we should assume that the computed value is 0.

The second statement means that the parameters are not mutually exclusive — we should sum all the biases and also the computed LOD.

There are multiple ways of how we can pass the bias in D3D12 (a good reference for LOD calculation and how DXBC sample instructions work internally is https://microsoft.github.io/DirectX-Specs/d3d/archive/D3D11_3_FunctionalSpec.htm):

It looks like there are two ways for us to cover the whole set of options:

Triang3l commented 4 years ago

Anisotropic filtering handling needs some work too — need to check if it should work at all when the filtering mode is not linear/linear/linear (whether anisotropic filtering overrides those or requires those) in guest fetch constants, and should be disabled for UseComputedLOD=false. Viva Piñata has broken vertices in one of the draw call (looks like a terrain patch — also has something in r0.yz, but that's a different story), and it involves a R8G8 texture with components apparently representing the low (high-frequency) and the high (low-frequency) parts of a single packed number. It's a vertex texture, without gradients (so no anisotropic filtering), and tfetch explicitly has point filtering, however for some reason the fetch constant has anisotropic filtering enabled, resulting in something totally broken.

Triang3l commented 4 years ago

Call of Duty 4 alpha uses anisotropic filtering with nearest-neighbor mip filtering (but linear magnification/minification filters), the way it works in general is really weird, it seems. Possibly should take precedence (assume linear/linear/linear — not sure how it should behave for basemap mip filtering though) when gradients are provided, but totally be ignored when they are not?

Triang3l commented 4 years ago

Mostly resolved in https://github.com/xenia-project/xenia/commit/8a64861ec08f0762fc17230efdda4a0c2bd59b9b.

However, there are still many things missing from our texture fetch implementation, but they would overcomplicate it while unlikely ever purposely used in games. Mainly things involving the LOD value:

That would require calculating the LOD somehow. CalculateLevelOfDetail may partially fulfill our needs, but it's available only in pixel shaders, and works only with implicit gradients (though explicit gradients can possibly be used by exploiting the parity of SV_Position). ALU LOD calculation is also possible, though may give different values than fixed-function texture sampling on the host probably, and would also require a lot of code, especially for anisotropic filtering. Another option (but memory- and bandwidth-consuming, though maybe tiled resource aliasing can be exploited) would be to use textures with the needed size filled with solid color with LOD values (something similar would also be needed for getBCF, but forcing zero would be a bit easier, everything could be mapped to a zero tile), though texture filtering precision needs to be taken into account here.

But for now, let's consider this solved until we find games requiring a more accurate implementation.