fix(shader): keep sRGB comparisons in the emulated runtime mode
(cherry picked from commit 5377951c552f2313c8f7a52b57bd7a54c5f7fb7f)
This commit is contained in:
parent
9e8b5a21bc
commit
82c04e4027
|
|
@ -1014,6 +1014,15 @@ if(BUILD_TESTING)
|
|||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
|
||||
endif()
|
||||
endforeach()
|
||||
add_test(NAME agc_driver_emulated_color_compare_srgb_decode COMMAND agc_driver_emulated_color_compare_tests)
|
||||
set_tests_properties(agc_driver_emulated_color_compare_srgb_decode PROPERTIES
|
||||
ENVIRONMENT "ANYPS5_NO_SHADER_CACHE=1;APS5_SRGB_SHADER_DECODE=1"
|
||||
SKIP_RETURN_CODE 77 WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
|
||||
set_tests_properties(agc_driver_emulated_color_compare agc_driver_emulated_color_compare_srgb_decode PROPERTIES TIMEOUT 30)
|
||||
if(WIN32)
|
||||
set_tests_properties(agc_driver_emulated_color_compare_srgb_decode PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
|
||||
endif()
|
||||
add_test(NAME agc_driver_f64_denorm_preserve_spirv COMMAND agc_driver_f64_fma_subnormals_tests --verify-spv-denorm-mode)
|
||||
set_tests_properties(agc_driver_f64_denorm_preserve_spirv PROPERTIES ENVIRONMENT "ANYPS5_NO_SHADER_CACHE=1" WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
|
||||
if(WIN32)
|
||||
|
|
|
|||
|
|
@ -2912,6 +2912,24 @@ void verifyCubeDepthCompareMode() {
|
|||
require(modes[selected].cube && (modes[selected].emulatedCompare & EmulatedCompare::Enabled) != 0u, "cube color comparison did not select its emulated runtime mode");
|
||||
}
|
||||
|
||||
void verifySrgbDepthCompareModes() {
|
||||
using namespace ShaderRecompiler;
|
||||
for (const auto decodeFormats : {0u, 1u, 2u, 3u}) {
|
||||
ImageResource image{};
|
||||
image.resourceClass = ImageResourceClass::Sampled;
|
||||
image.dimension = RdnaImageDimension::Dim2D;
|
||||
image.depthCompare = true;
|
||||
image.srgbDecodeCompatible = false;
|
||||
image.srgbDecodeFormats = decodeFormats;
|
||||
const auto modes = ResourceMaterializer::RuntimeImageModes(image);
|
||||
for (const auto format : {128u, 129u, 130u}) {
|
||||
const DescriptorValue descriptor{{0x100u, format << 20u, 0u, 0x90000facu, 0u, 0u, 0u, 0u}, 8u};
|
||||
const auto selected = ResourceMaterializer::RuntimeImageMode(image, descriptor, modes);
|
||||
require(!modes[selected].srgbDecode && (modes[selected].emulatedCompare & EmulatedCompare::Enabled) != 0u, "sRGB color comparison did not select its emulated runtime mode independently of decode support");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
try {
|
||||
using namespace ShaderRecompiler;
|
||||
|
|
@ -2958,6 +2976,7 @@ int main(int argc, char** argv) {
|
|||
verifyFunctionLdsBound();
|
||||
verifyGuardedNullPointers();
|
||||
verifyCubeDepthCompareMode();
|
||||
verifySrgbDepthCompareModes();
|
||||
#if ANYPS5_ENABLE_SPIRV_TOOLS
|
||||
const std::vector<std::uint32_t> minimalSpirv{
|
||||
0x07230203u, 0x00010000u, 0u, 5u, 0u,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <span>
|
||||
#include <stdexcept>
|
||||
|
|
@ -236,10 +237,11 @@ ShaderRecompiler::RecompileResult Compile(AgcDriver::VulkanDevice& device, std::
|
|||
return ShaderRecompiler::Recompile(request);
|
||||
}
|
||||
|
||||
void Run(AgcDriver::VulkanDevice& device, const Sampler& sampler, const char* name, bool offsets = false, bool useCache = false, bool array = false) {
|
||||
std::uint64_t Run(AgcDriver::VulkanDevice& device, const Sampler& sampler, const char* name, bool offsets = false, bool useCache = false, bool array = false, std::uint64_t expectedVariant = 0) {
|
||||
Output.fill(-1.0f);
|
||||
const std::span<const std::uint32_t> code = offsets ? std::span<const std::uint32_t>(OffsetCode) : array ? std::span<const std::uint32_t>(ArrayCode) : std::span<const std::uint32_t>(Code);
|
||||
const auto result = Compile(device, Format8888UNorm, sampler, code, useCache);
|
||||
if (expectedVariant != 0) Require(result.cacheHit && result.variantId == expectedVariant, std::string(name) + " did not reuse the compiled comparison artifact");
|
||||
for (const auto& binding : result.bindings) {
|
||||
Require(binding.role != ShaderRecompiler::DescriptorRole::GuestSamplers, "emulated comparison retained a sampler binding");
|
||||
Require(std::all_of(binding.imageSamplers.begin(), binding.imageSamplers.end(), [](auto mask) { return mask == 0u; }), "emulated comparison retained an unused sampler association");
|
||||
|
|
@ -251,6 +253,7 @@ void Run(AgcDriver::VulkanDevice& device, const Sampler& sampler, const char* na
|
|||
const float tolerance = sampler.filter == FilterPoint ? 0.0f : 1e-4f;
|
||||
Require(std::fabs(Output[tid] - expected) <= tolerance, std::string(name) + ": thread " + std::to_string(tid) + " compared to " + std::to_string(Output[tid]) + ", expected " + std::to_string(expected));
|
||||
}
|
||||
return result.variantId;
|
||||
}
|
||||
|
||||
constexpr std::uint32_t Select(std::uint32_t x, std::uint32_t y, std::uint32_t z, std::uint32_t w) {
|
||||
|
|
@ -306,9 +309,10 @@ bool BindsDepthCompare(const ShaderRecompiler::RecompileResult& result) {
|
|||
});
|
||||
}
|
||||
|
||||
void RunSrgbZero(AgcDriver::VulkanDevice& device, std::uint32_t format, const Sampler& sampler, const char* name) {
|
||||
void RunSrgbZero(AgcDriver::VulkanDevice& device, std::uint32_t format, const Sampler& sampler, const char* name, bool useCache, std::uint64_t expectedVariant) {
|
||||
Output.fill(-1.0f);
|
||||
const auto result = Compile(device, format, sampler);
|
||||
const auto result = Compile(device, format, sampler, Code, useCache);
|
||||
if (useCache) Require(result.cacheHit && result.variantId == expectedVariant, std::string(name) + " did not reuse the compiled comparison artifact");
|
||||
Require(!BindsDepthCompare(result), std::string(name) + " kept a depth-compare binding");
|
||||
device.Dispatch(result, 1, 1, 1, {}, reinterpret_cast<std::uintptr_t>(Code.data()));
|
||||
device.WaitIdle();
|
||||
|
|
@ -333,6 +337,8 @@ int main() {
|
|||
try {
|
||||
const auto device = OpenVulkanTestDevice();
|
||||
if (!device) return VulkanTestSkipped;
|
||||
const auto* forced = std::getenv("APS5_SRGB_SHADER_DECODE");
|
||||
if (forced != nullptr && std::string_view(forced) == "1") Require((device->Target().srgbDecodeFormats & 3u) == 3u, "forced R8 and RG8 sRGB shader decoding is unavailable");
|
||||
FillTexels();
|
||||
FillInput();
|
||||
RunCube(*device, {ClampEdge, FilterPoint}, "point cube, clamp to edge");
|
||||
|
|
@ -344,16 +350,22 @@ int main() {
|
|||
FillTexels();
|
||||
Require(BindsDepthCompare(Compile(*device, Format32Float, {ClampEdge, FilterBilinear})), "an R32 float texture left the native comparison path");
|
||||
Require(!BindsDepthCompare(Compile(*device, Format8888UNorm, {ClampEdge, FilterBilinear})), "a color texture kept a depth-compare binding");
|
||||
for (std::uint32_t function = 0; function < 8u; ++function) {
|
||||
const auto point = "point 8_8_8_8 srgb function " + std::to_string(function);
|
||||
const auto bilinear = "bilinear 8_8_8_8 srgb function " + std::to_string(function);
|
||||
RunSrgbZero(*device, Format8888Srgb, {ClampEdge, FilterPoint, BorderBlack, 0u, 0u, false, function}, point.c_str());
|
||||
RunSrgbZero(*device, Format8888Srgb, {ClampEdge, FilterBilinear, BorderBlack, 0u, 0u, false, function}, bilinear.c_str());
|
||||
for (const bool useCache : {false, true}) {
|
||||
const auto variant = useCache ? Run(*device, {ClampEdge, FilterPoint}, "cached UNORM before sRGB", false, true) : 0u;
|
||||
if (useCache) Require(variant != 0, "the cached comparison has no compiled artifact identity");
|
||||
for (const auto format : {Format8Srgb, Format8_8Srgb, Format8888Srgb}) {
|
||||
for (std::uint32_t function = 0; function < 8u; ++function) {
|
||||
for (const auto filter : {FilterPoint, FilterBilinear}) {
|
||||
const auto name = std::string(useCache ? "cached" : "uncached") + " sRGB format " + std::to_string(format) + " function " + std::to_string(function) + (filter == FilterPoint ? " point" : " bilinear");
|
||||
RunSrgbZero(*device, format, {ClampEdge, filter, BorderBlack, 0u, 0u, false, function}, name.c_str(), useCache, variant);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (useCache) Run(*device, {ClampEdge, FilterPoint}, "cached UNORM after sRGB", false, true, false, variant);
|
||||
}
|
||||
for (const auto format : {Format8Srgb, Format8_8Srgb, Format8888Srgb}) {
|
||||
Reject(*device, format, {ClampEdge, FilterBilinear}, "bilinear cube comparison requires DISABLE_CUBE_WRAP", CubeCode, true, true);
|
||||
}
|
||||
RunSrgbZero(*device, Format8Srgb, {ClampEdge, FilterPoint}, "point 8 srgb");
|
||||
RunSrgbZero(*device, Format8Srgb, {ClampEdge, FilterBilinear}, "bilinear 8 srgb");
|
||||
RunSrgbZero(*device, Format8_8Srgb, {ClampEdge, FilterPoint}, "point 8_8 srgb");
|
||||
RunSrgbZero(*device, Format8_8Srgb, {ClampEdge, FilterBilinear}, "bilinear 8_8 srgb");
|
||||
Run(*device, {ClampEdge, FilterPoint}, "point, clamp to edge");
|
||||
Run(*device, {ClampWrap, FilterPoint}, "point, wrap");
|
||||
Run(*device, {ClampWrap, FilterPoint}, "point, wrap with negative offsets", true);
|
||||
|
|
|
|||
|
|
@ -66,12 +66,21 @@ constexpr std::array<std::uint32_t, 9> SamplerCode(std::uint32_t word0) {
|
|||
};
|
||||
}
|
||||
|
||||
constexpr std::array<std::uint32_t, 15> MixedSamplerCode(std::uint32_t word0) {
|
||||
return {
|
||||
0x34060084u, 0x7e280280u, 0x7e2a0280u, 0x7e2c0280u, 0xf0bc0108u, 0x00610a14u, 0xbf8c3f70u,
|
||||
0xe0701000u, 0x80000a03u, word0, 0x00610a14u, 0xbf8c3f70u, 0xe0701004u, 0x80000a03u, 0xbf810000u,
|
||||
};
|
||||
}
|
||||
|
||||
alignas(256) constexpr auto LoadXyzw = LoadCode(0xfu);
|
||||
alignas(256) constexpr auto LoadXy = LoadCode(0x3u);
|
||||
alignas(256) constexpr auto StoreX = StoreCode(0x1u);
|
||||
alignas(256) constexpr auto StoreXy = StoreCode(0x3u);
|
||||
alignas(256) constexpr auto SampleLz = SamplerCode(0xf09c0f08u);
|
||||
alignas(256) constexpr auto Gather4Lz = SamplerCode(0xf11c0108u);
|
||||
alignas(256) constexpr auto MixedSampleLz = MixedSamplerCode(0xf09c0f08u);
|
||||
alignas(256) constexpr auto MixedGather4Lz = MixedSamplerCode(0xf11c0108u);
|
||||
|
||||
class GuestBlock {
|
||||
public:
|
||||
|
|
@ -235,6 +244,8 @@ int main() {
|
|||
CheckStoredLoad(*device, block, LoadXyzw, 0xfu, Srgb8, SwizzleXXX1, "8_SRGB image_load dmask:0xf X X X 1 of 8_UNORM image_stores");
|
||||
RequireRefused(*device, SampleLz, "image_sample_lz");
|
||||
RequireRefused(*device, Gather4Lz, "image_gather4_lz");
|
||||
RequireRefused(*device, MixedSampleLz, "image_sample_c_lz followed by image_sample_lz");
|
||||
RequireRefused(*device, MixedGather4Lz, "image_sample_c_lz followed by image_gather4_lz");
|
||||
std::puts("image sRGB load tests passed");
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
|
|
|
|||
|
|
@ -191,8 +191,8 @@ DecodedImage decodeImageDescriptor(const DescriptorValue& descriptor, const Imag
|
|||
if (((descriptorImageSwizzle(descriptor) >> (component * 3u)) & 7u) == 7u) throw std::runtime_error("selects a channel the converted image format does not have");
|
||||
}
|
||||
}
|
||||
decoded.srgbDecode = !storage && (srgbDecodeFormats & SrgbDecodeBit(format)) != 0u;
|
||||
if (decoded.srgbDecode && !base.srgbDecodeCompatible && !base.depthCompare) {
|
||||
decoded.srgbDecode = !storage && !base.depthCompare && (srgbDecodeFormats & SrgbDecodeBit(format)) != 0u;
|
||||
if (decoded.srgbDecode && !base.srgbDecodeCompatible) {
|
||||
throw std::runtime_error("samples or gathers an sRGB image the device cannot sample, which is not implemented");
|
||||
}
|
||||
if (storage || decoded.conversionFormat != IrBufferFormat::Invalid) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue