shader: validate texture mip ranges and channel selectors

This commit is contained in:
nmzik
2026-10-15 17:58:14 +02:00
parent 2caf2f7e4e
commit bcf13e101e
4 changed files with 81 additions and 28 deletions
@@ -87,6 +87,7 @@ bool ValidImageDescriptor(const DescriptorValue& descriptor, bool r128 = false)
type != Prospero::ImageType::kColor2DMsaa) {
return false;
}
if (!IsValidImageSwizzle(words[3] & 0xfffu)) return false;
const bool array = type == Prospero::ImageType::kColor1DArray ||
type == Prospero::ImageType::kColor2DArray ||
type == Prospero::ImageType::kColor2DMsaaArray ||
@@ -94,15 +95,15 @@ bool ValidImageDescriptor(const DescriptorValue& descriptor, bool r128 = false)
if (array && ((words[4] >> 16u) & 0x1fffu) > (words[4] & 0x1fffu)) {
return false;
}
const auto base_level = (words[3] >> 12u) & 0xfu;
const auto last_level = (words[3] >> 16u) & 0xfu;
if (type == Prospero::ImageType::kColor2DMsaa ||
type == Prospero::ImageType::kColor2DMsaaArray) {
const auto base_level = (descriptor.dwords[3] >> 12u) & 0xfu;
const auto fragments = (descriptor.dwords[3] >> 16u) & 0xfu;
const auto max_mip = (descriptor.dwords[5] >> 4u) & 0xfu;
return base_level == 0 && fragments >= 1 && fragments <= 3 &&
(r128 || max_mip == fragments);
return base_level == 0 && last_level >= 1 && last_level <= 3 &&
(r128 || max_mip == last_level);
}
return true;
return base_level <= last_level;
}
uint32_t DescriptorImageSwizzle(const DescriptorValue& descriptor) {
@@ -167,7 +168,7 @@ uint32_t ImageMipCount(const ImageResource& image, const DescriptorValue& descri
}
const auto base = (descriptor.dwords[3] >> 12u) & 0xfu;
const auto last = (descriptor.dwords[3] >> 16u) & 0xfu;
return base <= last ? last - base + 1u : 0u;
return last - base + 1u;
}
bool DecodeBufferDescriptor(const DescriptorValue& descriptor, ShaderBufferResource& result) {
@@ -831,10 +832,6 @@ static bool BuildResourceSpecialization(const ResourcePlan& program, ResourceSna
return SpecializationFail(fmt::format("image resource {} has an invalid class", i));
}
image.mip_count = ImageMipCount(base, descriptor);
if (image.mip_count == 0u) {
return SpecializationFail(
fmt::format("image descriptor {} has an invalid mip range", i));
}
if (NullImageDescriptor(descriptor)) {
image.numeric_class = base.atomic ? Prospero::TextureNumericClass::Uint
: Prospero::TextureNumericClass::Float;
+12
View File
@@ -66,6 +66,18 @@ inline uint8_t GetDstSel(uint32_t swizzle, uint32_t channel) {
return (swizzle >> (channel * 3u)) & 0x7u;
}
[[nodiscard]] inline bool IsValidImageSwizzle(uint32_t swizzle,
uint32_t component_count = 4) noexcept {
if ((swizzle & ~0xfffu) != 0) {
return false;
}
for (uint32_t channel = 0; channel < 4; channel++) {
const auto selector = GetDstSel(swizzle, channel);
if (selector > 1 && (selector < 4 || selector >= 4 + component_count)) return false;
}
return true;
}
struct ShaderClipSpaceTransform {
float scale[2] = {};
float offset[2] = {};