Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2347,6 +2347,7 @@ void VisitContentKey(const CompiledShader& shader, bool dataWords, bool movableB
packBits(binding.imageAtomic);
packBits(binding.samplerUnnormalized);
packBits(binding.samplerIntegerBorder);
packBits(binding.samplerCoordinatesIgnored);
packBits(binding.imageUnnormalized);
packBits(binding.imageUnnormalizedBaseLevel);
// Read-only elements are bound without a write set: an object built for one written set
Expand All @@ -2368,11 +2369,11 @@ std::vector<std::uint32_t> ShaderResources::ContentKey(const CompiledShader& sha
words += count;
};
for (const auto& binding : shader.program->bindings) {
addWords(19);
addWords(20);
addWords(binding.imageSamplers.size());
addWords(binding.imageShapes.size());
if ((dataWords && !movableBuffers) || !DataRole(binding.role)) addWords(binding.guestDescriptor.size());
for (const auto* bits : {&binding.imageWritten, &binding.samplerDepthCompare, &binding.imageDepthCompare, &binding.imageAtomic, &binding.samplerUnnormalized, &binding.samplerIntegerBorder, &binding.imageUnnormalized, &binding.imageUnnormalizedBaseLevel, &binding.bufferWritten}) addWords(bits->size() / 32u + (bits->size() % 32u != 0 ? 1u : 0u));
for (const auto* bits : {&binding.imageWritten, &binding.samplerDepthCompare, &binding.imageDepthCompare, &binding.imageAtomic, &binding.samplerUnnormalized, &binding.samplerIntegerBorder, &binding.samplerCoordinatesIgnored, &binding.imageUnnormalized, &binding.imageUnnormalizedBaseLevel, &binding.bufferWritten}) addWords(bits->size() / 32u + (bits->size() % 32u != 0 ? 1u : 0u));
}
key.reserve(words);
VisitContentKey(shader, dataWords, movableBuffers, [&](std::uint32_t word) { key.push_back(word); });
Expand Down Expand Up @@ -4082,7 +4083,14 @@ void ShaderResources::addImageBinding(const ShaderRecompiler::DescriptorBinding&
Require(binding.samplerDepthCompare.size() == binding.count, "guest sampler binding is missing depth comparison metadata");
Require(binding.samplerUnnormalized.empty() || binding.samplerUnnormalized.size() == binding.count, "guest sampler binding has unnormalized coordinate metadata of another size");
for (std::uint32_t element = 0; element < binding.count; ++element) {
const auto words = std::span<const std::uint32_t>(binding.guestDescriptor).subspan(static_cast<std::size_t>(element) * elementWords, elementWords);
auto guestWords = std::span<const std::uint32_t>(binding.guestDescriptor).subspan(static_cast<std::size_t>(element) * elementWords, elementWords);
std::array<std::uint32_t, 4> normalizedWords{};
if (element < binding.samplerCoordinatesIgnored.size() && binding.samplerCoordinatesIgnored[element]) {
std::copy(guestWords.begin(), guestWords.end(), normalizedWords.begin());
normalizedWords[0] &= ~(1u << 15u);
guestWords = normalizedWords;
}
const auto words = guestWords;
const bool compareEnable = binding.samplerDepthCompare.at(element);
const bool unnormalized = element < binding.samplerUnnormalized.size() && binding.samplerUnnormalized[element];
const bool integerBorder = element < binding.samplerIntegerBorder.size() && binding.samplerIntegerBorder[element];
Expand Down
3 changes: 2 additions & 1 deletion core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ void removeCacheDirectory(const std::filesystem::path& directory) {
}

bool sameBinding(const DescriptorBinding& left, const DescriptorBinding& right) {
return left.kind == right.kind && left.role == right.role && left.descriptorSet == right.descriptorSet && left.binding == right.binding && left.count == right.count && left.guestDescriptor == right.guestDescriptor && left.readOnly == right.readOnly && left.imageShape == right.imageShape && left.samplerDepthCompare == right.samplerDepthCompare && left.imageWritten == right.imageWritten && left.imageDepthCompare == right.imageDepthCompare && left.imageAtomic == right.imageAtomic && left.imageShapes == right.imageShapes && left.bufferAtomic == right.bufferAtomic && left.bufferWritten == right.bufferWritten && left.bufferRead == right.bufferRead && left.samplerUnnormalized == right.samplerUnnormalized && left.samplerIntegerBorder == right.samplerIntegerBorder && left.imageUnnormalized == right.imageUnnormalized && left.imageUnnormalizedBaseLevel == right.imageUnnormalizedBaseLevel && left.imageSamplers == right.imageSamplers;
return left.kind == right.kind && left.role == right.role && left.descriptorSet == right.descriptorSet && left.binding == right.binding && left.count == right.count && left.guestDescriptor == right.guestDescriptor && left.readOnly == right.readOnly && left.imageShape == right.imageShape && left.samplerDepthCompare == right.samplerDepthCompare && left.imageWritten == right.imageWritten && left.imageDepthCompare == right.imageDepthCompare && left.imageAtomic == right.imageAtomic && left.imageShapes == right.imageShapes && left.bufferAtomic == right.bufferAtomic && left.bufferWritten == right.bufferWritten && left.bufferRead == right.bufferRead && left.samplerUnnormalized == right.samplerUnnormalized && left.samplerIntegerBorder == right.samplerIntegerBorder && left.samplerCoordinatesIgnored == right.samplerCoordinatesIgnored && left.imageUnnormalized == right.imageUnnormalized && left.imageUnnormalizedBaseLevel == right.imageUnnormalizedBaseLevel && left.imageSamplers == right.imageSamplers;
}

bool sameBindings(const std::vector<DescriptorBinding>& left, const std::vector<DescriptorBinding>& right) {
Expand Down Expand Up @@ -176,6 +176,7 @@ DescriptorBinding sampleBinding(std::uint32_t seed) {
binding.bufferWritten = {false, false, true, true, false};
binding.samplerUnnormalized = {false, true, true};
binding.samplerIntegerBorder = {true, false, seed % 2 == 1};
binding.samplerCoordinatesIgnored = {false, seed % 2 == 0, true};
binding.imageUnnormalized = {true, false, seed % 2 == 0};
binding.imageUnnormalizedBaseLevel = {false, true, seed % 3 == 0};
binding.imageSamplers = {0x5u, 0u, 0x80000000u};
Expand Down
42 changes: 42 additions & 0 deletions core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4880,6 +4880,47 @@ void verifyUnnormalizedSamplers() {
require(proven(pixelOffsetNormalized, false) && implicitMasks.size() == 1u && (implicitMasks[0] & (spv::ImageOperandsConstOffsetMask | spv::ImageOperandsOffsetMask)) != 0u, "unnormalized texel offsets: a normalized pixel image_sample_o is not an implicit-LOD sample with its offset");
}

void verifyNullVolumeUnnormalizedSampler() {
using namespace ShaderRecompiler;
ImageResource volume{};
volume.resourceClass = ImageResourceClass::Sampled;
volume.numericClass = IrTextureNumericClass::Float;
volume.dimension = RdnaImageDimension::Dim3D;
volume.read = true;
ImageResource plane = volume;
plane.dimension = RdnaImageDimension::Dim2D;
SamplerResource sampler{};
sampler.uses = SamplerUseExplicitLod;
const DescriptorValue nullDescriptor{{0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u}, 8u};
const DescriptorValue volumeDescriptor{{0x00001000u, 0x03800000u, 0x0000c000u, 0xa0000facu, 3u, 0u, 0u, 0u}, 8u};
const DescriptorValue planeDescriptor{{0x00002000u, 0x03800000u, 0x0000c000u, 0x90000facu, 0u, 0u, 0u, 0u}, 8u};
const DescriptorValue unnormalized{{0x00008092u, 0x00fff000u, 0x02500000u, 0u}, 4u};
const auto populate = [&](std::vector<ImageResource> images, std::vector<DescriptorValue> descriptors) {
ShaderInfo info;
info.images = images;
info.samplers = {sampler};
for (std::uint32_t index = 0; index < images.size(); ++index) {
info.sampledPairs.push_back({index, 0u, 0u});
info.runtimeImageModes.push_back(ResourceMaterializer::RuntimeImageModes(images[index]));
}
ResourceSnapshot snapshot;
snapshot.images = descriptors;
snapshot.samplers = {unnormalized};
BindingAllocationResult allocation;
for (std::uint32_t index = 0; index < images.size(); ++index) allocation.layout.descriptors.push_back({DescriptorBindingForImage(images[index]), {index}});
allocation.layout.descriptors.push_back({DescriptorBindingKind::Samplers, {0u}});
DescriptorBindingBuilder{}.Populate(allocation, info, IrShaderStage::Compute, 0u, snapshot, {});
return allocation.bindings.back();
};
const auto nullOnly = populate({volume}, {nullDescriptor});
require(nullOnly.samplerUnnormalized == std::vector<bool>{false} && nullOnly.samplerCoordinatesIgnored == std::vector<bool>{true}, "unnormalized samplers: an S# paired only with a null 3D T# was refused or kept its unnormalized coordinates");
const DescriptorValue zeroSwizzle{{0x00003000u, 0x00100000u, 0u, 0xa0000000u, 0u, 0u, 0u, 0u}, 8u};
const auto constantAndNull = populate({volume, volume}, {zeroSwizzle, nullDescriptor});
require(constantAndNull.samplerUnnormalized == std::vector<bool>{false} && constantAndNull.samplerCoordinatesIgnored == std::vector<bool>{true}, "unnormalized samplers: an S# paired with a null 3D T# and a 3D T# whose channels all select constants was refused or kept its unnormalized coordinates");
expectFailure([&] { static_cast<void>(populate({volume}, {volumeDescriptor})); }, "samples a 1D-array, 2D-array, 3D, cube or multisampled image", "unnormalized samplers: a 3D T# was accepted");
expectFailure([&] { static_cast<void>(populate({volume, plane}, {nullDescriptor, planeDescriptor})); }, "samples a 1D-array, 2D-array, 3D, cube or multisampled image", "unnormalized samplers: an S# shared by a null 3D T# and a 2D T# was accepted");
}

void verifyUnusedUnnormalizedSampler() {
using namespace ShaderRecompiler;
ImageResource image{};
Expand Down Expand Up @@ -5955,6 +5996,7 @@ int main(int argc, char** argv) {
verifyCoherentBufferAccesses();
verifyUnnormalizedSamplers();
verifyUnusedUnnormalizedSampler();
verifyNullVolumeUnnormalizedSampler();
verifyWaveUniformValues();
verifyTwoLaneUniformValues();
verifyBdaReadFallbackFunctions();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ class ResourceMaterializer {
static std::uint32_t RuntimeImageMode(const ImageResource& image, const DescriptorValue& descriptor, std::span<const ImageResource> modes);
static void PrepareImageModes(ShaderInfo& info);
static const char* UnnormalizedSampleMismatch(const ImageResource& image);
static bool NullImageDescriptor(const ImageResource& image, const DescriptorValue& descriptor);
static ResolvedImageTables ResolveImageTables(const ShaderInfo& info, const ResourceSnapshot& snapshot, std::uint64_t memoKey = 0);
[[nodiscard]] IrResourcePlan ExtractPlan(const IrProgram& program) const;
static void CompactPlan(IrResourcePlan& plan);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,10 +182,11 @@ struct UnnormalizedProof {
std::vector<bool> samplers;
std::vector<bool> images;
std::vector<bool> imagesAtBaseLevel;
std::vector<bool> samplersIgnoreCoordinates;
};

UnnormalizedProof ProveUnnormalized(const ShaderInfo& info, const ResourceSnapshot& snapshot) {
UnnormalizedProof proof{std::vector<bool>(info.samplers.size()), std::vector<bool>(info.images.size()), std::vector<bool>(info.images.size())};
UnnormalizedProof proof{std::vector<bool>(info.samplers.size()), std::vector<bool>(info.images.size()), std::vector<bool>(info.images.size()), std::vector<bool>(info.samplers.size())};
for (std::uint32_t r = 0; r < info.samplers.size(); r++) {
if (snapshot.samplers.at(r).dwordCount != 4u) fail("sampler descriptor must contain four dwords");
const auto& sampler = info.samplers[r];
Expand All @@ -212,6 +213,8 @@ UnnormalizedProof ProveUnnormalized(const ShaderInfo& info, const ResourceSnapsh
if (sampler.depthCompare) {
failUnnormalized("is used with depth comparison");
}
bool sampled = false;
const char* nullMismatch = nullptr;
for (const auto& pair : info.sampledPairs) {
if (pair.sampler != r) {
continue;
Expand All @@ -221,12 +224,23 @@ UnnormalizedProof ProveUnnormalized(const ShaderInfo& info, const ResourceSnapsh
failUnnormalized("samples an image selected at run time");
}
const auto& image = info.runtimeImageModes.at(pair.image).at(ResourceMaterializer::RuntimeImageMode(base, snapshot.images.at(pair.image), info.runtimeImageModes.at(pair.image)));
if (const auto* reason = ResourceMaterializer::UnnormalizedSampleMismatch(image)) {
const auto* reason = ResourceMaterializer::UnnormalizedSampleMismatch(image);
if (reason != nullptr && ResourceMaterializer::NullImageDescriptor(base, snapshot.images.at(pair.image))) {
if (nullMismatch == nullptr) nullMismatch = reason;
continue;
}
if (reason != nullptr) {
failUnnormalized(reason);
}
if (image.constantSwizzle) continue;
sampled = true;
proof.images[pair.image] = true;
}
if (!sampled && nullMismatch != nullptr) {
proof.samplersIgnoreCoordinates[r] = true;
continue;
}
if (nullMismatch != nullptr) failUnnormalized(nullMismatch);
proof.samplers[r] = true;
}
for (std::uint32_t resource = 0; resource < info.images.size(); resource++) {
Expand Down Expand Up @@ -451,6 +465,7 @@ DescriptorBindingPlan DescriptorBindingBuilder::Prepare(const IrBindingLayout& l
for (const auto& pair : info.sampledPairs) if (pair.sampler == resource) compare |= info.images.at(pair.image).depthCompare && compareStates.at(pair.image) == 0u;
physical.samplerDepthCompare.push_back(compare);
physical.samplerUnnormalized.push_back(unnormalized.samplers.at(resource));
physical.samplerCoordinatesIgnored.push_back(unnormalized.samplersIgnoreCoordinates.at(resource));
const auto mode = 1u << (originals[element] & 1u);
physical.samplerIntegerBorder.push_back((samplerIntegerModes.at(resource) & mode) != 0u && (samplerFloatModes.at(resource) & mode) == 0u);
const auto& words = snapshot.samplers.at(resource).dwords;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1623,6 +1623,10 @@ std::vector<ImageResource> ResourceMaterializer::RuntimeImageModes(const ImageRe
return modes;
}

bool ResourceMaterializer::NullImageDescriptor(const ImageResource& image, const DescriptorValue& descriptor) {
return nullImageDescriptor(image, descriptor);
}

const char* ResourceMaterializer::UnnormalizedSampleMismatch(const ImageResource& image) {
if (image.table != NoTable) return "samples an image selected at run time";
if (image.constantSwizzle) return nullptr;
Expand Down
1 change: 1 addition & 0 deletions core/shader/recompiler/Recompiler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,7 @@ struct DescriptorBinding {
std::vector<bool> bufferWritten;
std::vector<bool> samplerUnnormalized;
std::vector<bool> samplerIntegerBorder;
std::vector<bool> samplerCoordinatesIgnored;
std::vector<bool> imageUnnormalized;
std::vector<bool> imageUnnormalizedBaseLevel;
std::vector<std::uint32_t> imageSamplers;
Expand Down
4 changes: 3 additions & 1 deletion core/shader/recompiler/ShaderDiskCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ namespace ShaderRecompiler::ShaderDiskCache {
static_assert(sizeof(CompiledShaderArtifact) == 240, "CompiledShaderArtifact changed: update the artifact encoder");
static_assert(sizeof(ShaderInvocation) == 200, "ShaderInvocation changed: update the invocation encoder");
static_assert(sizeof(RecompileResult) == 472, "RecompileResult changed: update EncodeResult and DecodeResult");
static_assert(sizeof(DescriptorBinding) == 592, "DescriptorBinding changed: update the binding encoder");
static_assert(sizeof(DescriptorBinding) == 632, "DescriptorBinding changed: update the binding encoder");
static_assert(sizeof(VertexAttribute) == 32, "VertexAttribute changed: update the attribute encoder");
static_assert(sizeof(VertexInput) == 16, "VertexInput changed: update the vertex input encoder");
static_assert(sizeof(FragmentParameter) == 16, "FragmentParameter changed: update the parameter encoder");
Expand Down Expand Up @@ -427,6 +427,7 @@ void encodeBinding(Writer& writer, const DescriptorBinding& binding) {
writer.Flags(binding.imageUnnormalized);
writer.Flags(binding.imageUnnormalizedBaseLevel);
writer.Flags(binding.samplerIntegerBorder);
writer.Flags(binding.samplerCoordinatesIgnored);
writer.Values(std::span<const std::uint32_t>(binding.imageSamplers));
writer.Flags(binding.bufferRead);
}
Expand Down Expand Up @@ -454,6 +455,7 @@ void decodeBinding(Reader& reader, DescriptorBinding& binding) {
reader.Flags(binding.imageUnnormalized);
reader.Flags(binding.imageUnnormalizedBaseLevel);
reader.Flags(binding.samplerIntegerBorder);
reader.Flags(binding.samplerCoordinatesIgnored);
reader.Values(binding.imageSamplers);
reader.Flags(binding.bufferRead);
}
Expand Down
2 changes: 1 addition & 1 deletion core/shader/recompiler/ShaderDiskCache.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

namespace ShaderRecompiler::ShaderDiskCache {

inline constexpr std::uint32_t FormatVersion = 37;
inline constexpr std::uint32_t FormatVersion = 38;

enum class LoadStatus {
Loaded,
Expand Down
Loading