mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-11-02 12:56:05 +00:00
fix(agc): sample formats that FORCE_DEGAMMA leaves unchanged without it
Co-Authored-By: Claude <[email protected]>
This commit is contained in:
1 parent
585075cb7e
commit
eeb1c4f034
6 files changed
+18
-3
No files matched your search
@@ -19,6 +19,7 @@ VkFormat SampledTextureFormat(const Context& context, std::uint32_t guestFormat)
|
||||
std::uint32_t SrgbCopyFormats(PFN_vkGetPhysicalDeviceFormatProperties formatProperties, VkPhysicalDevice physical, std::uint32_t decodeFormats);
|
||||
bool SrgbExpandsToRgba8(const Context& context, std::uint32_t guestFormat);
|
||||
bool IsSrgbTextureFormat(std::uint32_t guestFormat);
|
||||
bool IgnoresForcedDegamma(std::uint32_t guestFormat);
|
||||
std::optional<std::uint32_t> FindGuestTextureFormat(VkFormat format, std::uint32_t elementBytes);
|
||||
std::optional<std::uint32_t> FindGuestColorTargetFormat(VkFormat format, std::uint32_t elementBytes);
|
||||
std::uint32_t BytesPerElement(std::uint32_t guestFormat);
|
||||
|
||||
@@ -124,7 +124,7 @@ namespace AgcDriver::Graphics {
|
||||
}
|
||||
|
||||
bool ForcesDegammaOn(std::uint32_t guestFormat, std::uint32_t samplerMask, std::span<const std::shared_ptr<Sampler>> samplers) {
|
||||
if (IsSrgbTextureFormat(guestFormat)) return false;
|
||||
if (IsSrgbTextureFormat(guestFormat) || IgnoresForcedDegamma(guestFormat)) return false;
|
||||
for (std::uint32_t element = 0; element < 32u && element < samplers.size(); ++element) {
|
||||
if (((samplerMask >> element) & 1u) != 0u && samplers[element]->ForcesDegamma()) return true;
|
||||
}
|
||||
|
||||
@@ -170,6 +170,14 @@ bool IsSrgbTextureFormat(std::uint32_t guestFormat) {
|
||||
}
|
||||
}
|
||||
|
||||
bool IgnoresForcedDegamma(std::uint32_t guestFormat) {
|
||||
switch (guestFormat) {
|
||||
case 7u: case 8u: case 13u: case 22u: case 23u: case 24u: case 29u: case 36u: case 50u: case 64u: case 65u: case 66u: case 71u: case 77u:
|
||||
case 132u: case 133u: case 134u: case 136u: case 175u: case 176u: case 177u: case 178u: case 179u: case 180u: return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<std::uint32_t> FindGuestTextureFormat(VkFormat format, std::uint32_t elementBytes) {
|
||||
for (const auto& entry : kFormatLookup) {
|
||||
if (!entry.blockCompressed && entry.vkFormat == format && entry.bytesPerElement == elementBytes) return entry.guestFormat;
|
||||
|
||||
@@ -263,6 +263,8 @@ void RunTextureFormatTests() {
|
||||
reject([] { IsBlockCompressed(200); }, "unsupported guest texture format");
|
||||
for (const std::uint32_t format : {128u, 129u, 130u, 170u, 172u, 174u, 182u}) Require(IsSrgbTextureFormat(format), "guest format " + std::to_string(format) + " must be an sRGB texture format");
|
||||
for (const std::uint32_t format : {1u, 14u, 56u, 71u, 169u, 171u, 173u, 181u}) Require(!IsSrgbTextureFormat(format), "guest format " + std::to_string(format) + " must not be an sRGB texture format");
|
||||
for (const std::uint32_t format : {7u, 13u, 22u, 36u, 50u, 77u, 132u, 133u, 175u, 179u}) Require(IgnoresForcedDegamma(format), "guest format " + std::to_string(format) + " must sample the same through FORCE_DEGAMMA");
|
||||
for (const std::uint32_t format : {1u, 2u, 14u, 15u, 56u, 57u, 128u, 130u, 169u, 171u, 173u, 181u}) Require(!IgnoresForcedDegamma(format), "guest format " + std::to_string(format) + " must not sample the same through FORCE_DEGAMMA");
|
||||
convertedDccClearTests();
|
||||
singleDccKeysTests();
|
||||
packedFloatDccClearTests();
|
||||
|
||||
@@ -25,6 +25,8 @@ constexpr std::uint32_t Size = 4;
|
||||
constexpr std::uint32_t Format8888UNorm = 56;
|
||||
constexpr std::uint32_t Format8888Srgb = 130;
|
||||
constexpr std::uint32_t Format32Float = 22;
|
||||
constexpr std::uint32_t Format8888SNorm = 57;
|
||||
constexpr std::uint32_t FormatBc4UNorm = 175;
|
||||
constexpr std::uint32_t Type2D = 9;
|
||||
constexpr std::uint32_t FilterPoint = 0;
|
||||
constexpr std::uint32_t FilterBilinear = 1;
|
||||
@@ -173,7 +175,9 @@ int main() {
|
||||
Require(unormPlain[0] != unormPoint[0] || unormPlain[4] != unormPoint[4], "8_8_8_8_UNORM without FORCE_DEGAMMA sampled the decoded values");
|
||||
FillInput(false);
|
||||
RequireSame(Sample(*device, Format8888UNorm, FilterBilinear, ForceDegamma), forcedBilinear, "8_8_8_8_UNORM, bilinear", "through FORCE_DEGAMMA", "as 8_8_8_8_SRGB");
|
||||
Reject(*device, Format32Float, "guest format 22, which is not sRGB and has no sRGB view, is sampled through a sampler that forces sRGB decoding");
|
||||
RequireSame(Sample(*device, Format32Float, FilterPoint, ForceDegamma), Sample(*device, Format32Float, FilterPoint, 0u), "32_FLOAT, point");
|
||||
RequireSame(Sample(*device, FormatBc4UNorm, FilterPoint, ForceDegamma), Sample(*device, FormatBc4UNorm, FilterPoint, 0u), "BC4_UNORM, point");
|
||||
Reject(*device, Format8888SNorm, "guest format 57, which is not sRGB and has no sRGB view, is sampled through a sampler that forces sRGB decoding");
|
||||
std::puts("image sample force degamma tests passed");
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
|
||||
@@ -169,7 +169,7 @@
|
||||
- [Packed 16-bit textures](../../../core/libs/prx/libSceAgcDriver/Graphics/src/TextureFormat.cpp) (libSceAgcDriver) - `5_6_5`, `1_5_5_5` and `4_4_4_4` are viewed as R5G6B5, A1R5G5B5 and B4G4R4A4 (the 4-bit format every Vulkan device can sample; R4G4B4A4 is optional and lavapipe lacks it) with a swizzle that reads X from the low bits, and a DST_SEL of the missing W of `5_6_5` reads X. Measured on RDNA2 (gfx1035), not on the console: through `image_load` and `image_sample_lz`, X, Y, Z (and W of `1_5_5_5` and `4_4_4_4`) come from the low, middle and high fields, and W of `5_6_5` returns X (the low 5 bits), not 1.
|
||||
- [Min/max S# reduction](../../../core/libs/prx/libSceAgcDriver/Graphics/src/GuestSamplerResource.cpp) (libSceAgcDriver) - `FILTER_MODE` 1 and 2 use Vulkan's min and max reduction (the same `SQ_IMG_FILTER_MODE` values RADV programs). Measured on RDNA2 (gfx1035), not on the console: only texels of non-zero weight are reduced, and the weight is taken after rounding to the 8-bit subtexel grid (a sample within 1/512 texel of a centre reduces that texel alone); a driver with other `subTexelPrecisionBits` reduces a different set there. Gathers ignore the mode.
|
||||
- [Min/max S#](../../../core/libs/prx/libSceAgcDriver/Graphics/src/GuestSamplerResource.cpp) (libSceAgcDriver, shader recompiler) - throws with a linear mip filter, depth or color-texture compare, or bilinear or anisotropic filtering of an image the recompiler point-samples (sint, converted, depth-bits). With anisotropy the host sampler reduces over its own footprint; [RADV](https://github.com/openbsd/xenocara/blob/1b39033df8d928ec247ca64448c4a63c72302db7/lib/mesa/src/amd/vulkan/radv_sampler.c#L185-L232) programs the same S# for such a Vulkan sampler. Measured on RDNA2 (gfx1030 in [#5156](https://github.com/boykopovar/AnyPS5/pull/5156#issuecomment-6155265616), gfx1035 in #5821), not on the console: without derivatives (`image_sample_lz`), min or max with anisotropic bilinear returns the bilinear minimum or maximum and with anisotropic point the point result, at every ratio field 0 to 4; with derivatives (`image_sample_d`, a 4:1 footprint), anisotropic bilinear at ratio field 2 or 4 reduces over the texels of all its anisotropic taps (the minimum or maximum along the major axis), not one bilinear footprint. A host that is not AMD reduces over its own anisotropic footprint, and Vulkan leaves nearest filtering with anisotropy to the host driver.
|
||||
- [FORCE_DEGAMMA](../../../core/libs/prx/libSceAgcDriver/Graphics/src/Sampler.cpp) (libSceAgcDriver) - an S# that forces sRGB decoding adds nothing to an sRGB texture, as in shadPS4 (PS4). Measured on RDNA2 (gfx1035), not on the console: `8`, `8_8` and `8_8_8_8` sRGB textures sample bit for bit the same with and without the bit (point and bilinear; BC formats not measured). Other textures throw; on the same hardware their UNORM `8`, `8_8` and `8_8_8_8` forms sample bit for bit as the sRGB format (decoded before filtering).
|
||||
- [FORCE_DEGAMMA](../../../core/libs/prx/libSceAgcDriver/Graphics/src/Sampler.cpp) (libSceAgcDriver) - not measured on the console. A sampler that forces sRGB decoding throws for an SNORM `8`, `8_8` or `8_8_8_8` texture, which RDNA2 (gfx1031) reads bit for bit as the sRGB format of the same bytes, and for a format not measured on RDNA2. The rest follows gfx1035 and gfx1031 (point and bilinear): sRGB textures sample as without the bit, as in shadPS4 (PS4); UNORM `8`, `8_8`, `8_8_8_8`, BC1, BC2, BC3 and BC7 sample through their sRGB view (decoded before filtering); `16`, `16_16` and `16_16_16_16` UNORM, SNORM and FLOAT, `32`, `32_32` and `32_32_32_32` FLOAT, `10_11_11`, `2_10_10_10`, `5_9_9_9`, `5_6_5`, `1_5_5_5`, `4_4_4_4`, BC4, BC5 and BC6H sample as without the bit, as gfx1031 does.
|
||||
- [Tessellation factor ring](../../../core/libs/prx/libSceAgcDriver/State/src/Configuration.cpp) (libSceAgcDriver) - `sceAgcDriverSetTFRing` records the ring and `sceAgcDriverGetTFRing` reports it. Before a title sets one, it reports the console's default, 0xFF0000000 and 128 KiB, as measured in [PS5_Vulkan's hardware findings](https://github.com/mihawk-99/PS5_Vulkan/blob/fde9e3798c2ec1d8fccc90d5067cd6060490607f/docs/HARDWARE_FINDINGS.md). Nothing is written to the recorded ring: tessellated draws run as Vulkan tessellation stages, which keep their factors on the host, so a title that reads tessellation factors from the ring finds none. A null base or a zero size throws; [ps5-opengl's AGC runtime](https://github.com/blackbearreloaded/ps5-opengl/blob/67c873f985eaefe0a72f713529e5632eaa01139c/src/platform/ps5_agc_native_runtime.c) calls `sceAgcDriverSetTFRing(0, 0)` in its cleanup, and what that does on the console is unknown.
|
||||
- [VertexBufferReadSize](../../../core/libs/prx/libSceAgcDriver/Graphics/include/VertexInput.hpp) and the [vertex staging copy](../../../core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp) (libSceAgcDriver) - a vertex fetch whose index is at or past the descriptor's `num_records` no longer throws for `OOB_SELECT` 0 and 1. The copy still spans the whole fetch, but the bytes from `num_records * stride` onward read as zeros, so the out-of-range vertex is `(0, 0, 0, 0)`. Measured with `buffer_load_format_xyzw` (`idxen`) through the [hardware oracle](../HW_ORACLE.md) on RDNA2 gfx1036 for PPSA01325's word 3 `0x0004dfac` (`OOB_SELECT` 0) in #2241: indices 3, 4 and 5 over 3 records each return `00000000 00000000 00000000 00000000`, W included, unlike Vulkan `robustBufferAccess`, which returns `(0, 0, 0, 1)`. The zeros come from the record check, not from memory: stored values placed past the records are ignored, and a `num_records` 6 control returns them. `RESOURCE_LEVEL` 1, `OOB_SELECT` 1 and FORMAT 74 `32_32_32_FLOAT` give the same zeros, in wave32 and wave64; gfx1013 (the console) is not measured. `OOB_SELECT` 2 returns the stored values past the records and `OOB_SELECT` 3 compares `num_records` against the byte offset, both measured on the same setup in #2241; the two keep throwing past `num_records` here, since each needs its own rule. Zero-stride descriptors (`stride` 0) keep their separate byte-count check and are not covered here. Each out-of-range fetch is copied alone and outside the draw-snapshot cache, which is neither read nor written for it: a reused snapshot would carry another draw's bytes into the zero region, and a stored zero-padded copy would hand zeros to a later in-range draw at the same address. The valid prefix is still flushed for GPU writes before it is read.
|
||||
- [Draw snapshot buffer descriptors](../../../core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp) rewrite each affected array from element zero, preserving unchanged descriptors. MoltenVK 1.4.2 writes auxiliary buffer lengths at index `i` instead of `start + i` for partial array updates ([MVKDescriptorSet.mm, BufferAuxSize](https://github.com/KhronosGroup/MoltenVK/blob/v1.4.2/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm#L1051)). Per-element writes therefore let one buffer length replace another even when Vulkan buffer handles and ranges are correct.
|
||||
|
||||
Reference in new issue
Block a user