mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-24 04:46:56 +02:00
shader: simplify typed image bindings
This commit is contained in:
@@ -767,8 +767,10 @@ void TestDynamicStorageMipTracking() {
|
||||
ShaderComputeInputInfo compute{};
|
||||
CollectShaderInfo(fixture.program, {.compute = &compute});
|
||||
AllocateBindings(fixture.program, 0);
|
||||
const auto storage_kind = DescriptorBindingForImage(images[0]);
|
||||
Check(storage_kind.has_value(), "storage image has no descriptor binding");
|
||||
const auto *storage_binding =
|
||||
FindBinding(fixture.program.bindings, DescriptorBindingKind::Storage2D);
|
||||
FindBinding(fixture.program.bindings, *storage_kind);
|
||||
Check(storage_binding != nullptr &&
|
||||
storage_binding->resources == std::vector<uint32_t>({0, 1, 1, 1}),
|
||||
"dynamic storage mip descriptors were not expanded consecutively");
|
||||
@@ -1168,6 +1170,113 @@ void TestShaderInfoAndBindingLayout() {
|
||||
"binding layout did not collect live typed user-data values");
|
||||
}
|
||||
|
||||
void TestImageBindingAbi() {
|
||||
using NumericClass = Libs::Graphics::Prospero::TextureNumericClass;
|
||||
|
||||
Check(ImageBindingCount == 36u &&
|
||||
static_cast<uint32_t>(DescriptorBindingKind::Buffers) == 0u &&
|
||||
static_cast<uint32_t>(DescriptorBindingKind::Samplers) == 37u &&
|
||||
static_cast<uint32_t>(DescriptorBindingKind::Gds) == 38u &&
|
||||
static_cast<uint32_t>(DescriptorBindingKind::BdaPagetable) == 39u &&
|
||||
static_cast<uint32_t>(DescriptorBindingKind::FaultBuffer) == 40u &&
|
||||
static_cast<uint32_t>(DescriptorBindingKind::FlattenedSrt) == 41u &&
|
||||
static_cast<uint32_t>(DescriptorBindingKind::UserData) == 42u &&
|
||||
static_cast<uint32_t>(DescriptorBindingKind::Count) == 43u,
|
||||
"native descriptor binding anchors changed");
|
||||
|
||||
const std::array sampled_dimensions{
|
||||
Decoder::ImageDimension::Dim1D,
|
||||
Decoder::ImageDimension::Dim1DArray,
|
||||
Decoder::ImageDimension::Dim2D,
|
||||
Decoder::ImageDimension::Dim2DArray,
|
||||
Decoder::ImageDimension::Dim2DMsaa,
|
||||
Decoder::ImageDimension::Dim2DMsaaArray,
|
||||
Decoder::ImageDimension::Dim3D,
|
||||
};
|
||||
const std::array storage_dimensions{
|
||||
Decoder::ImageDimension::Dim1D, Decoder::ImageDimension::Dim1DArray,
|
||||
Decoder::ImageDimension::Dim2D, Decoder::ImageDimension::Dim2DArray,
|
||||
Decoder::ImageDimension::Dim3D,
|
||||
};
|
||||
const std::array sampled_classes{NumericClass::Float, NumericClass::Uint,
|
||||
NumericClass::Sint};
|
||||
const std::array storage_classes{NumericClass::Float, NumericClass::Uint};
|
||||
uint32_t index = 0;
|
||||
const auto CheckBinding =
|
||||
[&](ImageResourceClass resource_class, NumericClass numeric_class,
|
||||
Decoder::ImageDimension dimension, bool atomic) {
|
||||
ImageResource image;
|
||||
image.resource_class = resource_class;
|
||||
image.numeric_class = numeric_class;
|
||||
image.dimension = dimension;
|
||||
image.atomic = atomic;
|
||||
const auto kind = DescriptorBindingForImage(image);
|
||||
Check(kind.has_value() &&
|
||||
static_cast<uint32_t>(*kind) == FirstImageBinding + index &&
|
||||
ImageBindingIndex(*kind) == index &&
|
||||
ImageBindingResourceClass(*kind) == resource_class &&
|
||||
NativeBinding(ShaderType::Compute, *kind) ==
|
||||
FirstImageBinding + index &&
|
||||
NativeBinding(ShaderType::Pixel, *kind) ==
|
||||
static_cast<uint32_t>(DescriptorBindingKind::Count) +
|
||||
FirstImageBinding + index,
|
||||
"generated image descriptor binding changed ABI");
|
||||
index++;
|
||||
};
|
||||
for (const auto numeric_class : sampled_classes) {
|
||||
for (const auto dimension : sampled_dimensions) {
|
||||
CheckBinding(ImageResourceClass::Sampled, numeric_class, dimension,
|
||||
false);
|
||||
}
|
||||
}
|
||||
for (const auto numeric_class : storage_classes) {
|
||||
for (const auto dimension : storage_dimensions) {
|
||||
CheckBinding(ImageResourceClass::Storage, numeric_class, dimension,
|
||||
false);
|
||||
}
|
||||
}
|
||||
for (const auto dimension : storage_dimensions) {
|
||||
CheckBinding(ImageResourceClass::Storage, NumericClass::Uint, dimension,
|
||||
true);
|
||||
}
|
||||
Check(index == ImageBindingCount, "image descriptor ABI case count changed");
|
||||
|
||||
const auto Invalid = [](ImageResource image) {
|
||||
return !DescriptorBindingForImage(image).has_value();
|
||||
};
|
||||
ImageResource image;
|
||||
Check(Invalid(image), "untyped image received a descriptor binding");
|
||||
image.resource_class = ImageResourceClass::Sampled;
|
||||
image.numeric_class = NumericClass::Float;
|
||||
image.dimension = Decoder::ImageDimension::Unknown;
|
||||
Check(Invalid(image),
|
||||
"unknown sampled dimension received a descriptor binding");
|
||||
image.dimension = Decoder::ImageDimension::Dim2D;
|
||||
image.numeric_class = NumericClass::Unsupported;
|
||||
Check(Invalid(image),
|
||||
"unsupported sampled class received a descriptor binding");
|
||||
image.numeric_class = static_cast<NumericClass>(UINT32_MAX);
|
||||
Check(Invalid(image), "invalid sampled class received a descriptor binding");
|
||||
image.numeric_class = NumericClass::Float;
|
||||
image.dimension = static_cast<Decoder::ImageDimension>(UINT32_MAX);
|
||||
Check(Invalid(image),
|
||||
"invalid sampled dimension received a descriptor binding");
|
||||
image.dimension = Decoder::ImageDimension::Dim2D;
|
||||
image.atomic = true;
|
||||
Check(Invalid(image), "atomic sampled image received a descriptor binding");
|
||||
image.resource_class = ImageResourceClass::Storage;
|
||||
image.atomic = false;
|
||||
image.numeric_class = NumericClass::Sint;
|
||||
Check(Invalid(image), "signed storage image received a descriptor binding");
|
||||
image.numeric_class = NumericClass::Float;
|
||||
image.dimension = Decoder::ImageDimension::Dim2DMsaa;
|
||||
Check(Invalid(image),
|
||||
"multisampled storage image received a descriptor binding");
|
||||
image.dimension = Decoder::ImageDimension::Dim2D;
|
||||
image.atomic = true;
|
||||
Check(Invalid(image), "float atomic image received a descriptor binding");
|
||||
}
|
||||
|
||||
void TestGraphicsPushConstantLayout() {
|
||||
const auto AddUserData = [](Fixture &fixture, uint32_t count) {
|
||||
for (uint32_t index = 0; index < count; index++) {
|
||||
@@ -1312,6 +1421,7 @@ int main() {
|
||||
Run("dynamic FLAT address", TestDynamicFlatAddressesUseDma);
|
||||
Run("buffer swizzle specialization", TestBufferSwizzleSpecialization);
|
||||
Run("shader info and bindings", TestShaderInfoAndBindingLayout);
|
||||
Run("image binding ABI", TestImageBindingAbi);
|
||||
Run("graphics push constants", TestGraphicsPushConstantLayout);
|
||||
Run("resource limit", TestResourceLimitIsTransactional);
|
||||
Run("malformed memory kinds", TestMalformedMemoryKindsRejected);
|
||||
|
||||
@@ -9534,36 +9534,26 @@ public:
|
||||
auto Native = [](Kind kind) {
|
||||
return ShaderRecompiler::IR::NativeBinding(ShaderType::Compute, kind);
|
||||
};
|
||||
auto Count = [&](Kind kind) {
|
||||
const auto *binding = Binding(kind);
|
||||
if (binding == nullptr) {
|
||||
return 0u;
|
||||
for (const auto &binding : layout.descriptors) {
|
||||
const auto resource_class =
|
||||
ShaderRecompiler::IR::ImageBindingResourceClass(binding.kind);
|
||||
if (resource_class == ShaderRecompiler::IR::ImageResourceClass::None) {
|
||||
continue;
|
||||
}
|
||||
if (kind == Kind::Gds) {
|
||||
return 1u;
|
||||
const auto &image =
|
||||
compiled.program.info.images.at(binding.resources.front());
|
||||
bool supported =
|
||||
image.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim2D;
|
||||
if (resource_class == ShaderRecompiler::IR::ImageResourceClass::Sampled) {
|
||||
supported = supported ||
|
||||
image.dimension ==
|
||||
ShaderRecompiler::Decoder::ImageDimension::Dim1D ||
|
||||
image.dimension ==
|
||||
ShaderRecompiler::Decoder::ImageDimension::Dim1DArray;
|
||||
}
|
||||
return static_cast<u32>(binding->resources.size());
|
||||
};
|
||||
Require(
|
||||
test.name, "dispatch",
|
||||
Count(Kind::Sampled2DArray) == 0 && Count(Kind::Sampled3D) == 0 &&
|
||||
Count(Kind::SampledUint2DArray) == 0 &&
|
||||
Count(Kind::SampledUint3D) == 0 &&
|
||||
Count(Kind::SampledSint2DArray) == 0 &&
|
||||
Count(Kind::SampledSint3D) == 0 && Count(Kind::Storage1D) == 0 &&
|
||||
Count(Kind::Storage1DArray) == 0 &&
|
||||
Count(Kind::Storage2DArray) == 0 && Count(Kind::Storage3D) == 0 &&
|
||||
Count(Kind::StorageUint1D) == 0 &&
|
||||
Count(Kind::StorageUint1DArray) == 0 &&
|
||||
Count(Kind::StorageUint2DArray) == 0 &&
|
||||
Count(Kind::StorageUint3D) == 0 &&
|
||||
Count(Kind::StorageAtomic1D) == 0 &&
|
||||
Count(Kind::StorageAtomic1DArray) == 0 &&
|
||||
Count(Kind::StorageAtomic2DArray) == 0 &&
|
||||
Count(Kind::StorageAtomic3D) == 0,
|
||||
"unsupported array/3D image cases must provide matching Vulkan test "
|
||||
"views "
|
||||
"before dispatch");
|
||||
Require(test.name, "dispatch", supported,
|
||||
"unsupported image dimension needs a matching Vulkan test view");
|
||||
}
|
||||
|
||||
vk::ShaderModuleCreateInfo module_info{};
|
||||
module_info.sType = vk::StructureType::eShaderModuleCreateInfo;
|
||||
@@ -9652,34 +9642,10 @@ public:
|
||||
}
|
||||
pool_sizes.push_back({type, count});
|
||||
};
|
||||
add_pool_size(vk::DescriptorType::eStorageBuffer,
|
||||
Count(Kind::Buffers) +
|
||||
(Binding(Kind::BdaPagetable) != nullptr ? 1u : 0u) +
|
||||
(Binding(Kind::FaultBuffer) != nullptr ? 1u : 0u) +
|
||||
Count(Kind::Gds) +
|
||||
(Binding(Kind::FlattenedSrt) != nullptr ? 1u : 0u) +
|
||||
(Binding(Kind::UserData) != nullptr ? 1u : 0u));
|
||||
add_pool_size(
|
||||
vk::DescriptorType::eSampledImage,
|
||||
Count(Kind::Sampled1D) + Count(Kind::Sampled1DArray) +
|
||||
Count(Kind::Sampled2D) + Count(Kind::Sampled2DArray) +
|
||||
Count(Kind::Sampled3D) + Count(Kind::SampledUint1D) +
|
||||
Count(Kind::SampledUint1DArray) + Count(Kind::SampledUint2D) +
|
||||
Count(Kind::SampledUint2DArray) + Count(Kind::SampledUint3D) +
|
||||
Count(Kind::SampledSint1D) + Count(Kind::SampledSint1DArray) +
|
||||
Count(Kind::SampledSint2D) + Count(Kind::SampledSint2DArray) +
|
||||
Count(Kind::SampledSint3D));
|
||||
add_pool_size(
|
||||
vk::DescriptorType::eStorageImage,
|
||||
Count(Kind::Storage1D) + Count(Kind::Storage1DArray) +
|
||||
Count(Kind::Storage2D) + Count(Kind::Storage2DArray) +
|
||||
Count(Kind::Storage3D) + Count(Kind::StorageUint1D) +
|
||||
Count(Kind::StorageUint1DArray) + Count(Kind::StorageUint2D) +
|
||||
Count(Kind::StorageUint2DArray) + Count(Kind::StorageUint3D) +
|
||||
Count(Kind::StorageAtomic1D) + Count(Kind::StorageAtomic1DArray) +
|
||||
Count(Kind::StorageAtomic2D) + Count(Kind::StorageAtomic2DArray) +
|
||||
Count(Kind::StorageAtomic3D));
|
||||
add_pool_size(vk::DescriptorType::eSampler, Count(Kind::Samplers));
|
||||
for (const auto &binding : layout.descriptors) {
|
||||
add_pool_size(NativeDescriptorType(binding.kind),
|
||||
NativeDescriptorCount(binding));
|
||||
}
|
||||
vk::DescriptorPoolCreateInfo pool_info{};
|
||||
pool_info.sType = vk::StructureType::eDescriptorPoolCreateInfo;
|
||||
pool_info.maxSets = 1;
|
||||
@@ -9810,17 +9776,28 @@ public:
|
||||
writes.push_back(write);
|
||||
}
|
||||
const ShaderRecompiler::IR::DescriptorBinding *sampled = nullptr;
|
||||
constexpr std::array sampled_kinds{
|
||||
Kind::Sampled1D, Kind::Sampled1DArray, Kind::Sampled2D,
|
||||
Kind::SampledUint1D, Kind::SampledUint1DArray, Kind::SampledUint2D,
|
||||
Kind::SampledSint1D, Kind::SampledSint1DArray, Kind::SampledSint2D,
|
||||
};
|
||||
for (const auto kind : sampled_kinds) {
|
||||
if (const auto *candidate = Binding(kind); candidate != nullptr) {
|
||||
const ShaderRecompiler::IR::DescriptorBinding *storage = nullptr;
|
||||
const ShaderRecompiler::IR::DescriptorBinding *storage_uint = nullptr;
|
||||
const ShaderRecompiler::IR::DescriptorBinding *storage_atomic = nullptr;
|
||||
for (const auto &binding : layout.descriptors) {
|
||||
const auto resource_class =
|
||||
ShaderRecompiler::IR::ImageBindingResourceClass(binding.kind);
|
||||
if (resource_class == ShaderRecompiler::IR::ImageResourceClass::None) {
|
||||
continue;
|
||||
}
|
||||
const auto &image =
|
||||
compiled.program.info.images.at(binding.resources.front());
|
||||
if (resource_class == ShaderRecompiler::IR::ImageResourceClass::Sampled) {
|
||||
Require(test.name, "dispatch", sampled == nullptr,
|
||||
"Vulkan test harness needs separate sampled images for mixed "
|
||||
"descriptor classes");
|
||||
sampled = candidate;
|
||||
sampled = &binding;
|
||||
} else if (image.atomic) {
|
||||
storage_atomic = &binding;
|
||||
} else if (image.numeric_class == Prospero::TextureNumericClass::Float) {
|
||||
storage = &binding;
|
||||
} else {
|
||||
storage_uint = &binding;
|
||||
}
|
||||
}
|
||||
if (sampled != nullptr) {
|
||||
@@ -9841,9 +9818,6 @@ public:
|
||||
write.pImageInfo = sampled_infos.data();
|
||||
writes.push_back(write);
|
||||
}
|
||||
const auto *storage = Binding(Kind::Storage2D);
|
||||
const auto *storage_uint = Binding(Kind::StorageUint2D);
|
||||
const auto *storage_atomic = Binding(Kind::StorageAtomic2D);
|
||||
const auto BindStorage =
|
||||
[&](const ShaderRecompiler::IR::DescriptorBinding *binding,
|
||||
const Image *image, std::vector<vk::DescriptorImageInfo> *infos) {
|
||||
@@ -11837,24 +11811,18 @@ void RunCase(VulkanHarness *vulkan, const TestCase &test) {
|
||||
VulkanHarness::Image storage_image_uint;
|
||||
VulkanHarness::Buffer gds_buffer;
|
||||
vk::Sampler sampler = nullptr;
|
||||
const bool needs_sampled_image =
|
||||
Has(Kind::Sampled1D) || Has(Kind::Sampled1DArray) ||
|
||||
Has(Kind::Sampled2D) || Has(Kind::Sampled2DArray) ||
|
||||
Has(Kind::Sampled3D) || Has(Kind::SampledUint2D) ||
|
||||
Has(Kind::SampledUint1D) || Has(Kind::SampledUint1DArray) ||
|
||||
Has(Kind::SampledUint2DArray) || Has(Kind::SampledUint3D) ||
|
||||
Has(Kind::SampledSint2D) || Has(Kind::SampledSint1D) ||
|
||||
Has(Kind::SampledSint1DArray) || Has(Kind::SampledSint2DArray) ||
|
||||
Has(Kind::SampledSint3D);
|
||||
const bool needs_storage_image =
|
||||
Has(Kind::Storage1D) || Has(Kind::Storage1DArray) ||
|
||||
Has(Kind::Storage2D) || Has(Kind::Storage2DArray) ||
|
||||
Has(Kind::Storage3D) || Has(Kind::StorageUint2D) ||
|
||||
Has(Kind::StorageUint1D) || Has(Kind::StorageUint1DArray) ||
|
||||
Has(Kind::StorageUint2DArray) || Has(Kind::StorageUint3D) ||
|
||||
Has(Kind::StorageAtomic1D) || Has(Kind::StorageAtomic1DArray) ||
|
||||
Has(Kind::StorageAtomic2D) || Has(Kind::StorageAtomic2DArray) ||
|
||||
Has(Kind::StorageAtomic3D);
|
||||
bool needs_sampled_image = false;
|
||||
bool needs_storage_image = false;
|
||||
for (const auto &binding : compiled.program.bindings.descriptors) {
|
||||
const auto resource_class =
|
||||
ShaderRecompiler::IR::ImageBindingResourceClass(binding.kind);
|
||||
if (resource_class == ShaderRecompiler::IR::ImageResourceClass::Sampled) {
|
||||
needs_sampled_image = true;
|
||||
} else if (resource_class ==
|
||||
ShaderRecompiler::IR::ImageResourceClass::Storage) {
|
||||
needs_storage_image = true;
|
||||
}
|
||||
}
|
||||
const bool needs_sampler = Has(Kind::Samplers);
|
||||
const bool needs_gds = Has(Kind::Gds);
|
||||
if (needs_gds) {
|
||||
@@ -19760,7 +19728,7 @@ TestCase ImageLoadR32UintUsesIntegerSampledImage() {
|
||||
test.sampled_image_dwords_per_pixel = 1;
|
||||
test.user_data = MakeSampledTextureData(Prospero::BufferFormat::k32UInt);
|
||||
test.has_user_data = true;
|
||||
test.required_spirv = {"sampled_uint_2d", "OpTypeImage %uint",
|
||||
test.required_spirv = {"image_10", "OpTypeImage %uint",
|
||||
"OpImageFetch %v4uint"};
|
||||
return test;
|
||||
}
|
||||
@@ -19788,8 +19756,8 @@ TestCase ImageLoadR32SintUsesSignedSampledImage() {
|
||||
test.sampled_image_dwords_per_pixel = 1;
|
||||
test.user_data = MakeSampledTextureData(Prospero::BufferFormat::k32SInt);
|
||||
test.has_user_data = true;
|
||||
test.required_spirv = {"sampled_sint_2d", "OpTypeImage %int",
|
||||
"OpImageFetch %v4int", "OpBitcast %uint"};
|
||||
test.required_spirv = {"image_17", "OpTypeImage %int", "OpImageFetch %v4int",
|
||||
"OpBitcast %uint"};
|
||||
return test;
|
||||
}
|
||||
|
||||
@@ -19914,7 +19882,7 @@ TestCase ImageLoad1DUsesScalarCoordinate() {
|
||||
test.user_data[3] = static_cast<uint32_t>(Prospero::ImageType::kColor1D)
|
||||
<< 28u;
|
||||
test.has_user_data = true;
|
||||
test.required_spirv = {"sampled_uint_1d"};
|
||||
test.required_spirv = {"image_8"};
|
||||
return test;
|
||||
}
|
||||
|
||||
@@ -19950,7 +19918,7 @@ TestCase ImageGather2DInstructionWith1DDescriptor() {
|
||||
test.user_data[3] = static_cast<uint32_t>(Prospero::ImageType::kColor1D)
|
||||
<< 28u;
|
||||
test.has_user_data = true;
|
||||
test.required_spirv = {"sampled_1d", "OpImageQuerySizeLod",
|
||||
test.required_spirv = {"image_1", "OpImageQuerySizeLod",
|
||||
"OpImageSampleExplicitLod", "Floor"};
|
||||
test.forbidden_spirv = {"OpImageGather"};
|
||||
return test;
|
||||
@@ -19985,7 +19953,7 @@ TestCase ImageLoad1DArrayUsesLayerCoordinate() {
|
||||
test.user_data[3] = static_cast<uint32_t>(Prospero::ImageType::kColor1DArray)
|
||||
<< 28u;
|
||||
test.has_user_data = true;
|
||||
test.required_spirv = {"sampled_uint_1d_array"};
|
||||
test.required_spirv = {"image_9"};
|
||||
return test;
|
||||
}
|
||||
|
||||
@@ -20022,7 +19990,7 @@ TestCase ImageLoad1DArrayDescriptorUsesSelectedLayer() {
|
||||
<< 28u;
|
||||
test.user_data[4] = 1u | (1u << 16u);
|
||||
test.has_user_data = true;
|
||||
test.required_spirv = {"sampled_uint_1d"};
|
||||
test.required_spirv = {"image_8"};
|
||||
return test;
|
||||
}
|
||||
|
||||
@@ -20767,7 +20735,7 @@ TestCase ImageStoreR32SintUsesRawUintView() {
|
||||
test.storage_image_r32ui = std::vector<u32>(16, 0);
|
||||
test.expected_storage_image_r32ui = expected_image;
|
||||
test.required_spirv = {"OpCapability StorageImageWriteWithoutFormat",
|
||||
"storage_uint_2d"};
|
||||
"image_29"};
|
||||
test.forbidden_spirv = {"R32ui"};
|
||||
return test;
|
||||
}
|
||||
@@ -20797,7 +20765,7 @@ TestCase ImageStoreR32UintUsesFormatlessStorageImage() {
|
||||
test.storage_image_r32ui = std::vector<u32>(16, 0);
|
||||
test.expected_storage_image_r32ui = expected_image;
|
||||
test.required_spirv = {"OpCapability StorageImageWriteWithoutFormat",
|
||||
"storage_uint_2d"};
|
||||
"image_29"};
|
||||
test.forbidden_spirv = {"R32ui"};
|
||||
return test;
|
||||
}
|
||||
@@ -20831,7 +20799,7 @@ TestCase ImageStorePackedUintSaturatesChannels() {
|
||||
test.storage_image_r32ui = std::vector<u32>(16, 0);
|
||||
test.expected_storage_image_r32ui = std::move(expected_image);
|
||||
test.required_spirv = {"OpCapability StorageImageWriteWithoutFormat",
|
||||
"storage_uint_2d", "OpULessThan", "OpSelect"};
|
||||
"image_29", "OpULessThan", "OpSelect"};
|
||||
test.forbidden_spirv = {"R32ui"};
|
||||
return test;
|
||||
}
|
||||
@@ -20863,7 +20831,7 @@ TestCase ImageStorePackedUintHonorsSparseDmask() {
|
||||
test.storage_image_r32ui = std::vector<u32>(16, 0);
|
||||
test.expected_storage_image_r32ui = std::move(expected_image);
|
||||
test.required_spirv = {"OpCapability StorageImageWriteWithoutFormat",
|
||||
"storage_uint_2d"};
|
||||
"image_29"};
|
||||
test.forbidden_spirv = {"R32ui"};
|
||||
return test;
|
||||
}
|
||||
@@ -20924,9 +20892,9 @@ TestCase ImageStoreAndAtomicShareTypedBinding() {
|
||||
test.storage_image_r32ui = std::vector<u32>(16, 0);
|
||||
test.expected_storage_image_r32ui = std::move(expected_image);
|
||||
test.required_spirv = {"OpImageWrite", "OpImageTexelPointer", "R32ui",
|
||||
"storage_atomic_2d"};
|
||||
"image_34"};
|
||||
test.forbidden_spirv = {"StorageImageReadWithoutFormat",
|
||||
"StorageImageWriteWithoutFormat", "storage_uint_2d"};
|
||||
"StorageImageWriteWithoutFormat", "image_29"};
|
||||
return test;
|
||||
}
|
||||
|
||||
@@ -20965,8 +20933,8 @@ TestCase ImageStoreAndAtomicUseSeparateBindings() {
|
||||
"OpImageWrite",
|
||||
"OpImageTexelPointer",
|
||||
"R32ui",
|
||||
"storage_uint_2d",
|
||||
"storage_atomic_2d"};
|
||||
"image_29",
|
||||
"image_34"};
|
||||
return test;
|
||||
}
|
||||
|
||||
@@ -20997,10 +20965,10 @@ TestCase ImageAtomicVariants() {
|
||||
O::IMAGE_ATOMIC_UMIN, O::IMAGE_ATOMIC_AND,
|
||||
O::IMAGE_ATOMIC_OR, O::IMAGE_ATOMIC_XOR,
|
||||
O::BUFFER_STORE_DWORD, O::S_ENDPGM};
|
||||
test.required_spirv = {"OpImageTexelPointer", "R32ui", "storage_atomic_2d"};
|
||||
test.required_spirv = {"OpImageTexelPointer", "R32ui", "image_34"};
|
||||
test.forbidden_spirv = {"OpTypeSampler", "OpTypeSampledImage",
|
||||
"StorageImageReadWithoutFormat",
|
||||
"StorageImageWriteWithoutFormat", "storage_uint_2d"};
|
||||
"StorageImageWriteWithoutFormat", "image_29"};
|
||||
test.storage_image_rgba = MakeRgbaImage(4, 4);
|
||||
test.storage_image_r32ui = std::vector<u32>(16, 0);
|
||||
for (u32 i = 0; i < static_cast<u32>(std::size(initial)); i++) {
|
||||
@@ -23756,8 +23724,48 @@ void CheckImageSamplerSpecialization() {
|
||||
std::printf("[host] %-32s ok\n", "ImageSpecializationPipelineId");
|
||||
}
|
||||
|
||||
void CheckNativeImageDescriptorTypes() {
|
||||
using ShaderRecompiler::IR::DescriptorBindingKind;
|
||||
using ShaderRecompiler::IR::FirstImageBinding;
|
||||
using ShaderRecompiler::IR::FirstStorageImageBinding;
|
||||
|
||||
for (uint32_t value = FirstImageBinding;
|
||||
value < static_cast<uint32_t>(DescriptorBindingKind::Samplers);
|
||||
value++) {
|
||||
const auto expected = value < FirstStorageImageBinding
|
||||
? vk::DescriptorType::eSampledImage
|
||||
: vk::DescriptorType::eStorageImage;
|
||||
Require("NativeImageDescriptorTypes", "image binding",
|
||||
NativeDescriptorType(static_cast<DescriptorBindingKind>(value)) ==
|
||||
expected,
|
||||
"generated image binding has the wrong Vulkan descriptor type");
|
||||
}
|
||||
Require("NativeImageDescriptorTypes", "non-image bindings",
|
||||
NativeDescriptorType(DescriptorBindingKind::Samplers) ==
|
||||
vk::DescriptorType::eSampler &&
|
||||
NativeDescriptorType(DescriptorBindingKind::Buffers) ==
|
||||
vk::DescriptorType::eStorageBuffer &&
|
||||
NativeDescriptorType(DescriptorBindingKind::Gds) ==
|
||||
vk::DescriptorType::eStorageBuffer &&
|
||||
NativeDescriptorType(DescriptorBindingKind::BdaPagetable) ==
|
||||
vk::DescriptorType::eStorageBuffer &&
|
||||
NativeDescriptorType(DescriptorBindingKind::FaultBuffer) ==
|
||||
vk::DescriptorType::eStorageBuffer &&
|
||||
NativeDescriptorType(DescriptorBindingKind::FlattenedSrt) ==
|
||||
vk::DescriptorType::eStorageBuffer &&
|
||||
NativeDescriptorType(DescriptorBindingKind::UserData) ==
|
||||
vk::DescriptorType::eStorageBuffer,
|
||||
"non-image binding has the wrong Vulkan descriptor type");
|
||||
std::printf("[host] %-32s ok\n", "NativeImageDescriptorTypes");
|
||||
}
|
||||
|
||||
#if KYTY_PLATFORM != KYTY_PLATFORM_WINDOWS
|
||||
void CheckShaderRecompilerFatalContracts() {
|
||||
ExpectFatal("InvalidDescriptorBindingRejection", [] {
|
||||
(void)NativeDescriptorType(
|
||||
ShaderRecompiler::IR::DescriptorBindingKind::Count);
|
||||
});
|
||||
|
||||
ExpectFatal("WritableFlatStoreRejection", [] {
|
||||
const auto test = FlatStoreVariants();
|
||||
(void)CompileCase(test);
|
||||
@@ -25827,6 +25835,7 @@ int main(int argc, char **argv) {
|
||||
VulkanHarness vulkan;
|
||||
#endif
|
||||
CheckImageSamplerSpecialization();
|
||||
CheckNativeImageDescriptorTypes();
|
||||
CheckClipControlDepthClipState();
|
||||
CheckReferenceClockScale();
|
||||
CheckVulkan13FeatureRequirements();
|
||||
|
||||
+34
-24
@@ -5086,8 +5086,7 @@ void TestNewShaderRecompilerImageViewDimensions() {
|
||||
"1D derivative sample did not emit scalar SPIR-V gradients");
|
||||
Check(Common::ContainsStr(source, "OpImageQuerySizeLod"),
|
||||
"1D resource query did not emit a scalar size query");
|
||||
Check(SpirvSourceHasInstructionUsing(source, "OpAccessChain",
|
||||
"sampled_uint_1d"),
|
||||
Check(SpirvSourceHasInstructionUsing(source, "OpAccessChain", "image_8 "),
|
||||
"integer 1D load did not access the uint 1D descriptor binding");
|
||||
}
|
||||
|
||||
@@ -5124,11 +5123,10 @@ void TestNewShaderRecompilerStorageImage1DDescriptorVariants() {
|
||||
CheckSpirvBinaryValidates(result.spirv);
|
||||
|
||||
const auto source = DisassembleSpirvBinary(result.spirv);
|
||||
Check(SpirvSourceHasInstructionUsing(source, "OpAccessChain", "storage_1d "),
|
||||
Check(SpirvSourceHasInstructionUsing(source, "OpAccessChain", "image_22 "),
|
||||
"1D store did not access the 1D storage descriptor binding");
|
||||
Check(
|
||||
SpirvSourceHasInstructionUsing(source, "OpAccessChain",
|
||||
"storage_1d_array"),
|
||||
SpirvSourceHasInstructionUsing(source, "OpAccessChain", "image_23 "),
|
||||
"1D-array store did not access the 1D-array storage descriptor binding");
|
||||
}
|
||||
|
||||
@@ -5146,9 +5144,9 @@ void TestNewShaderRecompilerNullImageUsesCanonical2DView() {
|
||||
auto result = ShaderRecompiler::Recompile(shader, options);
|
||||
CheckSpirvBinaryValidates(result.spirv);
|
||||
const auto source = DisassembleSpirvBinary(result.spirv);
|
||||
Check(SpirvSourceHasInstructionUsing(source, "OpAccessChain", "sampled_2d "),
|
||||
Check(SpirvSourceHasInstructionUsing(source, "OpAccessChain", "image_3 "),
|
||||
"null image did not use the canonical 2D sampled descriptor binding");
|
||||
Check(!SpirvSourceHasInstructionUsing(source, "OpAccessChain", "sampled_1d "),
|
||||
Check(!SpirvSourceHasInstructionUsing(source, "OpAccessChain", "image_1 "),
|
||||
"null image retained the decoded 1D descriptor binding");
|
||||
}
|
||||
|
||||
@@ -5315,17 +5313,17 @@ void TestNewShaderRecompilerImageLoad2DMsaa() {
|
||||
result.program.info.images[0].dimension ==
|
||||
ShaderRecompiler::Decoder::ImageDimension::Dim2DMsaa,
|
||||
"2D-MSAA descriptor specialization lost the multisample dimension");
|
||||
Check(ShaderRecompiler::IR::FindBinding(
|
||||
result.program.bindings,
|
||||
ShaderRecompiler::IR::DescriptorBindingKind::Sampled2DMsaa) !=
|
||||
nullptr,
|
||||
const auto binding_kind = ShaderRecompiler::IR::DescriptorBindingForImage(
|
||||
result.program.info.images[0]);
|
||||
Check(binding_kind.has_value() &&
|
||||
ShaderRecompiler::IR::FindBinding(result.program.bindings,
|
||||
*binding_kind) != nullptr,
|
||||
"2D-MSAA image did not receive a multisampled descriptor binding");
|
||||
Check(SpirvContainsTypeImage(result.spirv, 1, 0, 1, 1),
|
||||
"SPIR-V binary does not contain a multisampled 2D image type");
|
||||
CheckSpirvBinaryValidates(result.spirv);
|
||||
const auto source = DisassembleSpirvBinary(result.spirv);
|
||||
Check(SpirvSourceHasInstructionUsing(source, "OpAccessChain",
|
||||
"sampled_2d_msaa"),
|
||||
Check(SpirvSourceHasInstructionUsing(source, "OpAccessChain", "image_5 "),
|
||||
"2D-MSAA load did not access its multisampled descriptor");
|
||||
Check(SpirvSourceHasInstructionUsing(source, "OpImageFetch", " Sample "),
|
||||
"2D-MSAA load did not emit the fragment ID as a SPIR-V Sample operand");
|
||||
@@ -5424,7 +5422,7 @@ void TestNewShaderRecompilerStorageImage3DDescriptorVariant() {
|
||||
CheckSpirvBinaryValidates(result.spirv);
|
||||
|
||||
const auto source = DisassembleSpirvBinary(result.spirv);
|
||||
Check(SpirvSourceHasInstructionUsing(source, "OpAccessChain", "storage_3d"),
|
||||
Check(SpirvSourceHasInstructionUsing(source, "OpAccessChain", "image_26 "),
|
||||
"storage image store did not access the 3D storage descriptor binding");
|
||||
}
|
||||
|
||||
@@ -5460,14 +5458,13 @@ void TestNewShaderRecompilerStorageImage2DDescriptorOverridesMimg3D() {
|
||||
CheckSpirvBinaryValidates(result.spirv);
|
||||
|
||||
const auto source = DisassembleSpirvBinary(result.spirv);
|
||||
Check(SpirvSourceHasInstructionUsing(source, "OpAccessChain", "storage_2d"),
|
||||
Check(SpirvSourceHasInstructionUsing(source, "OpAccessChain", "image_24 "),
|
||||
"2D descriptor storage image store did not access the base storage "
|
||||
"binding");
|
||||
Check(!SpirvSourceHasInstructionUsing(source, "OpAccessChain",
|
||||
"storage_2d_array"),
|
||||
Check(!SpirvSourceHasInstructionUsing(source, "OpAccessChain", "image_25 "),
|
||||
"2D descriptor storage image store unexpectedly used the array storage "
|
||||
"binding");
|
||||
Check(!SpirvSourceHasInstructionUsing(source, "OpAccessChain", "storage_3d"),
|
||||
Check(!SpirvSourceHasInstructionUsing(source, "OpAccessChain", "image_26 "),
|
||||
"2D descriptor storage image store unexpectedly used the 3D storage "
|
||||
"binding");
|
||||
}
|
||||
@@ -10342,12 +10339,25 @@ void TestNewShaderRecompilerNativeBindingPlan() {
|
||||
auto result = ShaderRecompiler::Recompile(shader, options);
|
||||
const auto *buffers = ShaderRecompiler::IR::FindBinding(
|
||||
result.program.bindings, BindingKind::Buffers);
|
||||
const auto *sampled = ShaderRecompiler::IR::FindBinding(
|
||||
result.program.bindings, BindingKind::Sampled2D);
|
||||
const auto *storage = ShaderRecompiler::IR::FindBinding(
|
||||
result.program.bindings, BindingKind::Storage2D);
|
||||
const auto *atomic_storage = ShaderRecompiler::IR::FindBinding(
|
||||
result.program.bindings, BindingKind::StorageAtomic2D);
|
||||
const ShaderRecompiler::IR::DescriptorBinding *sampled = nullptr;
|
||||
const ShaderRecompiler::IR::DescriptorBinding *storage = nullptr;
|
||||
const ShaderRecompiler::IR::DescriptorBinding *atomic_storage = nullptr;
|
||||
for (const auto &image : result.program.info.images) {
|
||||
const auto kind = ShaderRecompiler::IR::DescriptorBindingForImage(image);
|
||||
if (!kind.has_value()) {
|
||||
continue;
|
||||
}
|
||||
const auto *binding =
|
||||
ShaderRecompiler::IR::FindBinding(result.program.bindings, *kind);
|
||||
if (image.resource_class ==
|
||||
ShaderRecompiler::IR::ImageResourceClass::Sampled) {
|
||||
sampled = binding;
|
||||
} else if (image.atomic) {
|
||||
atomic_storage = binding;
|
||||
} else {
|
||||
storage = binding;
|
||||
}
|
||||
}
|
||||
const auto *samplers = ShaderRecompiler::IR::FindBinding(
|
||||
result.program.bindings, BindingKind::Samplers);
|
||||
Check(buffers != nullptr && buffers->resources.size() == 2,
|
||||
|
||||
Reference in New Issue
Block a user