mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-20 10:56:58 +02:00
Validate texture descriptor fields
This commit is contained in:
@@ -62,6 +62,13 @@ bool NullImageDescriptor(const DescriptorValue& descriptor) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool ValidImageDescriptor(const DescriptorValue& descriptor, bool r128 = false) {
|
bool ValidImageDescriptor(const DescriptorValue& descriptor, bool r128 = false) {
|
||||||
|
const auto& words = descriptor.dwords;
|
||||||
|
// Reject texture descriptors with nonzero reserved bits.
|
||||||
|
if ((words[1] & 0x20000000u) != 0u || (words[2] & 0xf0003000u) != 0u ||
|
||||||
|
(!r128 && ((words[4] & 0xe000e000u) != 0u || (words[5] & 0xf9000000u) != 0u ||
|
||||||
|
(words[6] & 0x00007b00u) != 0u))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
const auto type = static_cast<Prospero::ImageType>((descriptor.dwords[3] >> 28u) & 0xfu);
|
const auto type = static_cast<Prospero::ImageType>((descriptor.dwords[3] >> 28u) & 0xfu);
|
||||||
const auto format = static_cast<Prospero::BufferFormat>((descriptor.dwords[1] >> 20u) & 0x1ffu);
|
const auto format = static_cast<Prospero::BufferFormat>((descriptor.dwords[1] >> 20u) & 0x1ffu);
|
||||||
if (type < Prospero::ImageType::kColor1D || format == Prospero::BufferFormat::kInvalid ||
|
if (type < Prospero::ImageType::kColor1D || format == Prospero::BufferFormat::kInvalid ||
|
||||||
@@ -72,6 +79,13 @@ bool ValidImageDescriptor(const DescriptorValue& descriptor, bool r128 = false)
|
|||||||
type != Prospero::ImageType::kColor2DMsaa) {
|
type != Prospero::ImageType::kColor2DMsaa) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
const bool array = type == Prospero::ImageType::kColor1DArray ||
|
||||||
|
type == Prospero::ImageType::kColor2DArray ||
|
||||||
|
type == Prospero::ImageType::kColor2DMsaaArray ||
|
||||||
|
type == Prospero::ImageType::kCube;
|
||||||
|
if (array && ((words[4] >> 16u) & 0x1fffu) > (words[4] & 0x1fffu)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (type == Prospero::ImageType::kColor2DMsaa ||
|
if (type == Prospero::ImageType::kColor2DMsaa ||
|
||||||
type == Prospero::ImageType::kColor2DMsaaArray) {
|
type == Prospero::ImageType::kColor2DMsaaArray) {
|
||||||
const auto base_level = (descriptor.dwords[3] >> 12u) & 0xfu;
|
const auto base_level = (descriptor.dwords[3] >> 12u) & 0xfu;
|
||||||
|
|||||||
@@ -650,6 +650,21 @@ void TestGuardedDirectImageTable() {
|
|||||||
snapshot.flattened_srt[specialization.images[0].indirect_mapping_offset] == 32u &&
|
snapshot.flattened_srt[specialization.images[0].indirect_mapping_offset] == 32u &&
|
||||||
memory.reads == 34u && memory.descriptor_reads == 32u,
|
memory.reads == 34u && memory.descriptor_reads == 32u,
|
||||||
"direct table did not retain all 32 reachable descriptors");
|
"direct table did not retain all 32 reachable descriptors");
|
||||||
|
const auto captured_word = (table - memory.base) / 4u + 16u * 8u;
|
||||||
|
const auto original_descriptor = snapshot.images[16].dwords;
|
||||||
|
const std::array<uint32_t, 8> captured_invalid{
|
||||||
|
0x101f0000u, 0xcb500000u, 0x001fc01fu, 0xd0970facu,
|
||||||
|
0x86000000u, 0x00500003u, 0x00000400u, 0x00005204u};
|
||||||
|
std::copy(captured_invalid.begin(), captured_invalid.end(),
|
||||||
|
memory.words.begin() + captured_word);
|
||||||
|
Check(MaterializeResources(plan, runtime, snapshot, specialization) &&
|
||||||
|
snapshot.images.size() == 32u &&
|
||||||
|
snapshot.flattened_srt[specialization.images[0].indirect_mapping_offset] == 32u &&
|
||||||
|
std::ranges::all_of(snapshot.images[16].dwords,
|
||||||
|
[](uint32_t word) { return word == 0u; }),
|
||||||
|
"captured non-descriptor record became a host image or lost its key mapping");
|
||||||
|
std::copy(original_descriptor.begin(), original_descriptor.end(),
|
||||||
|
memory.words.begin() + captured_word);
|
||||||
memory.words[(table - memory.base) / 4u + 31u * 8u] = 0x987u;
|
memory.words[(table - memory.base) / 4u + 31u * 8u] = 0x987u;
|
||||||
Check(MaterializeResources(plan, runtime, snapshot, specialization) &&
|
Check(MaterializeResources(plan, runtime, snapshot, specialization) &&
|
||||||
snapshot.images[31].dwords[0] == 0x987u,
|
snapshot.images[31].dwords[0] == 0x987u,
|
||||||
@@ -684,6 +699,78 @@ void TestGuardedDirectImageTable() {
|
|||||||
"batched descriptor read crossed the 48-bit endpoint");
|
"batched descriptor read crossed the 48-bit endpoint");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestImageDescriptorFields() {
|
||||||
|
constexpr std::array<std::pair<uint32_t, uint32_t>, 5> reserved{
|
||||||
|
{{1u, 0x20000000u}, {2u, 0xf0003000u}, {4u, 0xe000e000u},
|
||||||
|
{5u, 0xf9000000u}, {6u, 0x00007b00u}}};
|
||||||
|
for (const bool r128 : {false, true}) {
|
||||||
|
Fixture fixture;
|
||||||
|
std::array<Value, 8> words;
|
||||||
|
for (uint32_t word = 0; word < words.size(); ++word) {
|
||||||
|
words[word] = fixture.UserData(word);
|
||||||
|
}
|
||||||
|
const auto image = fixture.Image(words);
|
||||||
|
const auto sampler = fixture.Sampler({Value(0u), Value(0u), Value(0u), Value(0u)});
|
||||||
|
MemoryInfo memory;
|
||||||
|
memory.kind = ResourceKind::Image;
|
||||||
|
memory.image_dimension = Decoder::ImageDimension::Dim2D;
|
||||||
|
memory.image_r128 = r128;
|
||||||
|
fixture.Emit(ValueOpcode::ImageSampleRaw, {image, sampler, fixture.ImageAddress()},
|
||||||
|
fixture.AddMemory(memory, 0x80));
|
||||||
|
fixture.PlanAndTrack();
|
||||||
|
auto plan = ExtractResourcePlan(fixture.program);
|
||||||
|
std::array<uint32_t, 8> user_data{};
|
||||||
|
user_data[0] = 0x100u;
|
||||||
|
user_data[1] = static_cast<uint32_t>(
|
||||||
|
Libs::Graphics::Prospero::BufferFormat::k32_32_32_32Float) << 20u;
|
||||||
|
user_data[3] = Libs::Graphics::DstSel(4, 5, 6, 7) |
|
||||||
|
(static_cast<uint32_t>(Libs::Graphics::Prospero::ImageType::kColor2D) << 28u);
|
||||||
|
const SrtRuntime runtime{.user_data = user_data};
|
||||||
|
ResourceSnapshot snapshot;
|
||||||
|
ResourceSpecialization specialization;
|
||||||
|
const auto is_null = [&] {
|
||||||
|
return std::ranges::all_of(snapshot.images[0].dwords,
|
||||||
|
[](uint32_t word) { return word == 0u; });
|
||||||
|
};
|
||||||
|
Check(MaterializeResources(plan, runtime, snapshot, specialization) &&
|
||||||
|
snapshot.images[0].dwords == user_data,
|
||||||
|
"valid texture descriptor was rejected");
|
||||||
|
for (const auto [word, mask] : reserved) {
|
||||||
|
for (uint32_t bits = mask; bits != 0u; bits &= bits - 1u) {
|
||||||
|
const auto bit = bits & (0u - bits);
|
||||||
|
user_data[word] |= bit;
|
||||||
|
Check(MaterializeResources(plan, runtime, snapshot, specialization) &&
|
||||||
|
(r128 && word >= 4u ? snapshot.images[0].dwords == user_data : is_null()),
|
||||||
|
"reserved descriptor bits or ignored R128 upper words were misclassified");
|
||||||
|
user_data[word] &= ~bit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
user_data[5] = 0x06800000u;
|
||||||
|
user_data[6] = 0x010880ffu;
|
||||||
|
user_data[7] = 0x1234u;
|
||||||
|
Check(MaterializeResources(plan, runtime, snapshot, specialization) &&
|
||||||
|
snapshot.images[0].dwords == user_data,
|
||||||
|
"defined mip-statistics, PRT, or metadata fields were treated as reserved");
|
||||||
|
user_data[3] |= 3u << 16u;
|
||||||
|
Check(MaterializeResources(plan, runtime, snapshot, specialization) &&
|
||||||
|
snapshot.images[0].dwords == user_data,
|
||||||
|
"view LAST_LEVEL above physical MAX_MIP was rejected");
|
||||||
|
if (!r128) {
|
||||||
|
user_data[3] = (user_data[3] & 0x0fffffffu) |
|
||||||
|
(static_cast<uint32_t>(Libs::Graphics::Prospero::ImageType::kColor2DArray) << 28u);
|
||||||
|
user_data[4] = 3u | (4u << 16u);
|
||||||
|
Check(MaterializeResources(plan, runtime, snapshot, specialization) && is_null(),
|
||||||
|
"array view starting after its last slice was accepted");
|
||||||
|
for (const auto base : {1u, 3u}) {
|
||||||
|
user_data[4] = 3u | (base << 16u);
|
||||||
|
Check(MaterializeResources(plan, runtime, snapshot, specialization) &&
|
||||||
|
snapshot.images[0].dwords == user_data,
|
||||||
|
"valid array view with a nonzero base slice was rejected");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void TestUniformScalarBufferImage() {
|
void TestUniformScalarBufferImage() {
|
||||||
Fixture fixture(ShaderType::Pixel);
|
Fixture fixture(ShaderType::Pixel);
|
||||||
std::array<Value, 4> material_words;
|
std::array<Value, 4> material_words;
|
||||||
@@ -2411,6 +2498,7 @@ int main() {
|
|||||||
Run("dynamic storage mips", TestDynamicStorageMipTracking);
|
Run("dynamic storage mips", TestDynamicStorageMipTracking);
|
||||||
Run("invariant indirect images", TestInvariantIndirectImageMaterialization);
|
Run("invariant indirect images", TestInvariantIndirectImageMaterialization);
|
||||||
Run("guarded direct image table", TestGuardedDirectImageTable);
|
Run("guarded direct image table", TestGuardedDirectImageTable);
|
||||||
|
Run("image descriptor fields", TestImageDescriptorFields);
|
||||||
Run("draw-uniform scalar image", TestUniformScalarBufferImage);
|
Run("draw-uniform scalar image", TestUniformScalarBufferImage);
|
||||||
Run("SRT runtime", TestSrtFlatteningAndRuntimeMemoization);
|
Run("SRT runtime", TestSrtFlatteningAndRuntimeMemoization);
|
||||||
Run("dynamic SRT", TestDynamicSrtReadRemainsExplicit);
|
Run("dynamic SRT", TestDynamicSrtReadRemainsExplicit);
|
||||||
|
|||||||
Reference in New Issue
Block a user