graphics: intersect texture views with resource mips

This commit is contained in:
nmzik
2026-08-16 09:56:50 +02:00
parent 430de9bd15
commit af1ab60786
3 changed files with 122 additions and 28 deletions
@@ -405,10 +405,14 @@ static bool IsSupportedStorageTextureDescriptor(const ShaderRecompiler::IR::Imag
const bool supported_swizzle = const bool supported_swizzle =
IsValidImageSwizzle(swizzle) && IsValidImageSwizzle(swizzle) &&
(swizzle == DstSel(4, 5, 6, 7) || !resource.read || resource.atomic); (swizzle == DstSel(4, 5, 6, 7) || !resource.read || resource.atomic);
const auto view_last_level =
resource.mip_mode == ShaderRecompiler::IR::ImageMipMode::DynamicStorage
? descriptor.LastLevel()
: std::min(descriptor.LastLevel(), descriptor.MaxMip());
return (is_1d || is_1d_array || is_2d || is_2d_array || is_3d) && supported_tile && return (is_1d || is_1d_array || is_2d || is_2d_array || is_3d) && supported_tile &&
descriptor.BaseLevel() <= descriptor.LastLevel() && descriptor.BaseLevel() <= view_last_level && view_last_level <= descriptor.MaxMip() &&
descriptor.LastLevel() <= descriptor.MaxMip() && descriptor.MinLod() == 0 && descriptor.MinLod() == 0 && supported_swizzle && descriptor.BCSwizzle() == 0 &&
supported_swizzle && descriptor.BCSwizzle() == 0 && !descriptor.MsaaDepth(); !descriptor.MsaaDepth();
} }
static bool IsSupportedStorageTextureEncoding(const ShaderTextureResource& descriptor) { static bool IsSupportedStorageTextureEncoding(const ShaderTextureResource& descriptor) {
@@ -629,11 +633,15 @@ RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageResource& reso
const auto type = TextureType(descriptor); const auto type = TextureType(descriptor);
const bool multisampled = IsMultisampledTexture(type); const bool multisampled = IsMultisampledTexture(type);
const auto levels = multisampled ? 1u : static_cast<uint32_t>(descriptor.MaxMip()) + 1u; const auto levels = multisampled ? 1u : static_cast<uint32_t>(descriptor.MaxMip()) + 1u;
const auto tile = descriptor.TileMode(); const bool dynamic_storage =
const bool depth_tile = tile == Prospero::TileMode::kDepth; storage && resource.mip_mode == ShaderRecompiler::IR::ImageMipMode::DynamicStorage;
const bool msaa_tile = depth_tile || tile == Prospero::TileMode::kRenderTarget; const auto view_last_level =
const bool msaa_array = type == Prospero::ImageType::kColor2DMsaaArray; !multisampled && !dynamic_storage ? std::min(last_level, descriptor.MaxMip()) : last_level;
if ((!multisampled && (base_level > last_level || last_level >= levels)) || const auto tile = descriptor.TileMode();
const bool depth_tile = tile == Prospero::TileMode::kDepth;
const bool msaa_tile = depth_tile || tile == Prospero::TileMode::kRenderTarget;
const bool msaa_array = type == Prospero::ImageType::kColor2DMsaaArray;
if ((!multisampled && (base_level > view_last_level || view_last_level >= levels)) ||
(multisampled && (multisampled &&
(base_level != 0 || last_level == 0 || last_level > 3 || (base_level != 0 || last_level == 0 || last_level > 3 ||
descriptor.MaxMip() != last_level || !msaa_tile || descriptor.MaxMip() != last_level || !msaa_tile ||
@@ -652,7 +660,7 @@ RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageResource& reso
} }
const auto samples = multisampled ? 1u << last_level : 1u; const auto samples = multisampled ? 1u << last_level : 1u;
const auto view_levels = const auto view_levels =
multisampled ? 1u : static_cast<uint32_t>(last_level - base_level) + 1u; multisampled ? 1u : static_cast<uint32_t>(view_last_level - base_level) + 1u;
const auto depth = static_cast<uint32_t>(descriptor.Depth()) + 1u; const auto depth = static_cast<uint32_t>(descriptor.Depth()) + 1u;
const auto format = descriptor.Format(); const auto format = descriptor.Format();
const bool sampled_numeric_class = const bool sampled_numeric_class =
@@ -261,9 +261,10 @@ void RenderExecutor::DispatchDirect(uint64_t submit_id, RenderCommandBuffer& buf
r.Base40(), static_cast<uint32_t>(r.Type()), static_cast<uint32_t>(r.Format()), r.Base40(), static_cast<uint32_t>(r.Type()), static_cast<uint32_t>(r.Format()),
static_cast<uint32_t>(r.Width5()) + 1u, static_cast<uint32_t>(r.Height5()) + 1u, static_cast<uint32_t>(r.Width5()) + 1u, static_cast<uint32_t>(r.Height5()) + 1u,
static_cast<uint32_t>(r.Depth()) + 1u, static_cast<uint32_t>(r.Depth()) + 1u,
std::max<uint32_t>(static_cast<uint32_t>(r.LastLevel()), r.Type() == Prospero::ImageType::kColor2DMsaa ||
static_cast<uint32_t>(r.MaxMip())) + r.Type() == Prospero::ImageType::kColor2DMsaaArray
1u, ? 1u
: static_cast<uint32_t>(r.MaxMip()) + 1u,
static_cast<uint32_t>(r.TileMode())); static_cast<uint32_t>(r.TileMode()));
} }
for (uint32_t i = 0; i < program.info.samplers.size(); i++) { for (uint32_t i = 0; i < program.info.samplers.size(); i++) {
+101 -16
View File
@@ -6561,43 +6561,75 @@ public:
std::end(mipped_storage.fields), std::end(mipped_storage.fields),
mipped_storage_descriptor.dwords.begin()); mipped_storage_descriptor.dwords.begin());
mipped_storage_descriptor.dword_count = 8; mipped_storage_descriptor.dword_count = 8;
auto overwide_mipped_storage = mipped_storage;
overwide_mipped_storage.fields[3] =
(overwide_mipped_storage.fields[3] & ~(0xfu << 16u)) | (4u << 16u);
ShaderRecompiler::IR::DescriptorValue
overwide_mipped_storage_descriptor{};
std::copy(std::begin(overwide_mipped_storage.fields),
std::end(overwide_mipped_storage.fields),
overwide_mipped_storage_descriptor.dwords.begin());
overwide_mipped_storage_descriptor.dword_count = 8;
auto mipped_storage_resource = storage_resource; auto mipped_storage_resource = storage_resource;
mipped_storage_resource.mip_mode = mipped_storage_resource.mip_mode =
ShaderRecompiler::IR::ImageMipMode::DynamicStorage; ShaderRecompiler::IR::ImageMipMode::DynamicStorage;
mipped_storage_resource.mip_count = 3; mipped_storage_resource.mip_count = 3;
auto sampled_overwide_resource = storage_resource;
sampled_overwide_resource.kind =
ShaderRecompiler::IR::ResourceKind::ImageUint;
sampled_overwide_resource.read = true;
sampled_overwide_resource.written = false;
auto plain_mipped_storage_binding = auto plain_mipped_storage_binding =
RenderExecutorTestAccess::ResolveTexture(executor, storage_resource,
mipped_storage_descriptor);
auto mipped_storage_binding = RenderExecutorTestAccess::ResolveTexture(
executor, mipped_storage_resource, mipped_storage_descriptor);
auto overwide_mipped_storage_binding =
RenderExecutorTestAccess::ResolveTexture( RenderExecutorTestAccess::ResolveTexture(
executor, storage_resource, mipped_storage_descriptor); executor, storage_resource, overwide_mipped_storage_descriptor);
auto mipped_storage_binding = auto sampled_overwide_resolved = RenderExecutorTestAccess::ResolveTexture(
RenderExecutorTestAccess::ResolveTexture( executor, sampled_overwide_resource,
executor, mipped_storage_resource, mipped_storage_descriptor); overwide_mipped_storage_descriptor);
DescriptorCache::PreparedBindings mipped_prepared{}; DescriptorCache::PreparedBindings mipped_prepared{};
auto mipped_program = auto mipped_program = std::make_shared<ShaderRecompiler::IR::Program>();
std::make_shared<ShaderRecompiler::IR::Program>();
mipped_program->info.images.push_back(storage_resource); mipped_program->info.images.push_back(storage_resource);
mipped_program->info.images.push_back(mipped_storage_resource); mipped_program->info.images.push_back(mipped_storage_resource);
mipped_program->info.images.push_back(storage_resource);
mipped_program->info.images.push_back(sampled_overwide_resource);
auto mipped_snapshot = auto mipped_snapshot =
std::make_shared<ShaderRecompiler::IR::ResourceSnapshot>(); std::make_shared<ShaderRecompiler::IR::ResourceSnapshot>();
mipped_snapshot->images.assign(2, mipped_storage_descriptor); mipped_snapshot->images = {mipped_storage_descriptor,
mipped_storage_descriptor,
overwide_mipped_storage_descriptor,
overwide_mipped_storage_descriptor};
mipped_prepared.program = std::move(mipped_program); mipped_prepared.program = std::move(mipped_program);
mipped_prepared.snapshot = std::move(mipped_snapshot); mipped_prepared.snapshot = std::move(mipped_snapshot);
mipped_prepared.resources.images.push_back( mipped_prepared.resources.images.push_back(
std::move(plain_mipped_storage_binding)); std::move(plain_mipped_storage_binding));
mipped_prepared.resources.images.push_back( mipped_prepared.resources.images.push_back(
std::move(mipped_storage_binding)); std::move(mipped_storage_binding));
mipped_prepared.resources.images.push_back(
std::move(overwide_mipped_storage_binding));
mipped_prepared.resources.images.push_back(
std::move(sampled_overwide_resolved));
executor.RebindImages(scheduler.Current(), mipped_prepared); executor.RebindImages(scheduler.Current(), mipped_prepared);
auto &plain_mipped_binding = mipped_prepared.resources.images[0]; auto &plain_mipped_binding = mipped_prepared.resources.images[0];
auto &mipped_binding = mipped_prepared.resources.images[1]; auto &mipped_binding = mipped_prepared.resources.images[1];
auto &overwide_mipped_binding = mipped_prepared.resources.images[2];
auto &sampled_overwide_binding = mipped_prepared.resources.images[3];
plain_mipped_binding.layout = vk::ImageLayout::eGeneral; plain_mipped_binding.layout = vk::ImageLayout::eGeneral;
mipped_binding.layout = vk::ImageLayout::eGeneral; mipped_binding.layout = vk::ImageLayout::eGeneral;
overwide_mipped_binding.layout = vk::ImageLayout::eGeneral;
sampled_overwide_binding.layout = vk::ImageLayout::eGeneral;
auto plain_view_desc = plain_mipped_binding.desc; auto plain_view_desc = plain_mipped_binding.desc;
plain_view_desc.view_info.level_count = 1; plain_view_desc.view_info.level_count = 1;
Require(name, "dynamic storage mip views", Require(name, "dynamic storage mip views",
plain_mipped_binding.desc.view_info.base_level == 1 && plain_mipped_binding.desc.view_info.base_level == 1 &&
plain_mipped_binding.desc.view_info.level_count == 3 && plain_mipped_binding.desc.view_info.level_count == 3 &&
plain_mipped_binding.mip_views.empty() && plain_mipped_binding.mip_views.empty() &&
plain_mipped_binding.image_view == texture_cache.FindTexture( plain_mipped_binding.image_view ==
plain_mipped_binding.image_id, plain_view_desc) && texture_cache.FindTexture(plain_mipped_binding.image_id,
plain_view_desc) &&
mipped_binding.desc.info.resources.levels == 4 && mipped_binding.desc.info.resources.levels == 4 &&
mipped_binding.desc.view_info.base_level == 1 && mipped_binding.desc.view_info.base_level == 1 &&
mipped_binding.desc.view_info.level_count == 3 && mipped_binding.desc.view_info.level_count == 3 &&
@@ -6615,6 +6647,28 @@ public:
.imageView == mipped_binding.mip_views[2], .imageView == mipped_binding.mip_views[2],
"base-1 through last-3 storage view did not create three " "base-1 through last-3 storage view did not create three "
"ordered one-level descriptors"); "ordered one-level descriptors");
Require(name, "over-wide fixed storage mip view",
overwide_mipped_storage.LastLevel() == 4 &&
overwide_mipped_storage.MaxMip() == 3 &&
overwide_mipped_binding.image_id ==
plain_mipped_binding.image_id &&
overwide_mipped_binding.desc.info.resources.levels == 4 &&
overwide_mipped_binding.desc.view_info.base_level == 1 &&
overwide_mipped_binding.desc.view_info.level_count == 3 &&
overwide_mipped_binding.mip_views.empty() &&
overwide_mipped_binding.image_view ==
plain_mipped_binding.image_view,
"fixed storage view was not intersected with its physical mip "
"range before Vulkan acquisition");
Require(name, "over-wide sampled mip view",
sampled_overwide_binding.image_id ==
plain_mipped_binding.image_id &&
sampled_overwide_binding.desc.info.resources.levels == 4 &&
sampled_overwide_binding.desc.view_info.base_level == 1 &&
sampled_overwide_binding.desc.view_info.level_count == 3 &&
sampled_overwide_binding.mip_views.empty() &&
sampled_overwide_binding.image_view != nullptr,
"sampled view was not intersected with its physical mip range");
auto srgb_storage = storage; auto srgb_storage = storage;
constexpr auto srgb_format = constexpr auto srgb_format =
static_cast<uint32_t>(Prospero::BufferFormat::k8_8_8_8Srgb); static_cast<uint32_t>(Prospero::BufferFormat::k8_8_8_8Srgb);
@@ -18967,6 +19021,11 @@ ShaderTextureResource Ppsa01340MipRangeStorageTextureDescriptor() {
0x00700030u, 0xb07b0000u, 0x0002ac3cu}}; 0x00700030u, 0xb07b0000u, 0x0002ac3cu}};
} }
ShaderTextureResource Ppsa01340OverwideMipStorageTextureDescriptor() {
return {{0x0346c000u, 0xc4b00000u, 0x007fc07fu, 0x90990facu, 0x00000000u,
0x00700080u, 0x00000000u, 0x00000000u}};
}
ShaderRecompiler::IR::ImageResource Ppsa01530MaxMipStorageTextureResource() { ShaderRecompiler::IR::ImageResource Ppsa01530MaxMipStorageTextureResource() {
auto resource = BasicBgraStorageTextureResource(); auto resource = BasicBgraStorageTextureResource();
resource.kind = ShaderRecompiler::IR::ResourceKind::StorageImageUint; resource.kind = ShaderRecompiler::IR::ResourceKind::StorageImageUint;
@@ -19102,7 +19161,11 @@ ShaderTextureResource AtomicStorageTextureDescriptor() {
descriptor.fields[3] = descriptor.fields[3] =
(descriptor.fields[3] & ~(0x1fu << 20u)) | (descriptor.fields[3] & ~(0x1fu << 20u)) |
(static_cast<uint32_t>(Prospero::TileMode::kStandard256B) << 20u); (static_cast<uint32_t>(Prospero::TileMode::kStandard256B) << 20u);
} else if (std::strcmp(kind, "mip") == 0) { } else if (std::strcmp(kind, "base-mip-out-of-resource") == 0) {
descriptor.fields[3] |= (1u << 12u) | (1u << 16u);
} else if (std::strcmp(kind, "dynamic-mip-out-of-resource") == 0) {
resource.mip_mode = ShaderRecompiler::IR::ImageMipMode::DynamicStorage;
resource.mip_count = 2;
descriptor.fields[3] |= 1u << 16u; descriptor.fields[3] |= 1u << 16u;
} else if (std::strcmp(kind, "inverted-mip-range") == 0) { } else if (std::strcmp(kind, "inverted-mip-range") == 0) {
descriptor.fields[3] |= 1u << 12u; descriptor.fields[3] |= 1u << 12u;
@@ -19246,6 +19309,27 @@ void CheckBasicStorageTextureDescriptor() {
ValidateStorageTexture(BasicBgraStorageTextureResource(), mip_range, ValidateStorageTexture(BasicBgraStorageTextureResource(), mip_range,
0xa30000); 0xa30000);
const auto overwide_mip = Ppsa01340OverwideMipStorageTextureDescriptor();
Require(
"BasicStorageTexture", "PPSA01340 over-wide mip view",
overwide_mip.Base40() == 0x346c00000ull &&
overwide_mip.Width5() + 1u == 512 &&
overwide_mip.Height5() + 1u == 512 && overwide_mip.BaseLevel() == 0 &&
overwide_mip.LastLevel() == 9 && overwide_mip.MaxMip() == 8 &&
overwide_mip.Format() == Prospero::BufferFormat::k32_32_32_32UInt &&
overwide_mip.TileMode() == Prospero::TileMode::kStandard64KB,
"captured over-wide storage mip view is malformed");
TileSizeAlign overwide_size{};
TileGetTextureTotalSize(overwide_mip.Format(), overwide_mip.Width5() + 1u,
overwide_mip.Height5() + 1u, 1,
overwide_mip.MaxMip() + 1u, overwide_mip.TileMode(),
false, overwide_size);
Require("BasicStorageTexture", "PPSA01340 over-wide mip footprint",
overwide_size.size == 0x560000 && overwide_size.align == 0x10000,
"captured nine-level Standard64KB footprint changed");
ValidateStorageTexture(Ppsa01530MaxMipStorageTextureResource(), overwide_mip,
overwide_size.size);
const auto r16_float = Ppsa02527R16FloatStorageTextureDescriptor(); const auto r16_float = Ppsa02527R16FloatStorageTextureDescriptor();
Require("BasicStorageTexture", "PPSA02527 R16F descriptor", Require("BasicStorageTexture", "PPSA02527 R16F descriptor",
r16_float.Base40() == 0xce350000ull && r16_float.Base40() == 0xce350000ull &&
@@ -19542,12 +19626,13 @@ void CheckBasicStorageTextureDescriptor() {
GetModuleFileNameA(nullptr, path, MAX_PATH) != 0, GetModuleFileNameA(nullptr, path, MAX_PATH) != 0,
"GetModuleFileName failed"); "GetModuleFileName failed");
for (const char *kind : for (const char *kind :
{"resource", "type", "standard256b-volume", "mip", {"resource", "type", "standard256b-volume",
"inverted-mip-range", "swizzle", "base-mip-out-of-resource", "dynamic-mip-out-of-resource",
"linear-rgb1-read", "bgra-read", "r16-float-read", "r8-unorm-read", "inverted-mip-range", "swizzle", "linear-rgb1-read", "bgra-read",
"yzwx-read", "reserved-swizzle", "array-base-out-of-range", "reserved", "r16-float-read", "r8-unorm-read", "yzwx-read", "reserved-swizzle",
"uint-format", "uint-resource-float-format", "atomic-format", "array-base-out-of-range", "reserved", "uint-format",
"depth-tile-read", "depth-tile-extent", "depth-tile-fmask"}) { "uint-resource-float-format", "atomic-format", "depth-tile-read",
"depth-tile-extent", "depth-tile-fmask"}) {
std::string command = std::string("\"") + path + std::string command = std::string("\"") + path +
"\" --storage-texture-descriptor-death " + kind; "\" --storage-texture-descriptor-death " + kind;
std::vector<char> mutable_command(command.begin(), command.end()); std::vector<char> mutable_command(command.begin(), command.end());