[spirv] mark descriptor indices as non-uniform

This commit is contained in:
ryana 2026-04-28 21:43:57 +08:00
parent 6e5158fd11
commit 1d601ea5ae
No known key found for this signature in database
GPG key ID: 1B0D2A9833DC2348
4 changed files with 82 additions and 14 deletions

View file

@ -14,6 +14,40 @@
namespace Shader::Backend::SPIRV {
namespace {
class DescriptorIndex {
public:
explicit DescriptorIndex(EmitContext& ctx_, const IR::Value& index,
spv::Capability capability)
: ctx{ctx_}, id{index.IsImmediate() ? ctx.Const(index.U32()) : ctx.Def(index)},
is_non_uniform{ctx.profile.support_descriptor_nonuniform_indexing &&
!index.IsImmediate()} {
if (!is_non_uniform) {
return;
}
if (ctx.profile.supported_spirv < 0x00010400) {
ctx.AddExtension("SPV_EXT_descriptor_indexing");
}
ctx.AddCapability(spv::Capability::ShaderNonUniform);
ctx.AddCapability(capability);
Decorate(id);
}
Id Value() const {
return id;
}
void Decorate(Id object) const {
if (is_non_uniform) {
ctx.Decorate(object, spv::Decoration::NonUniform);
}
}
private:
EmitContext& ctx;
Id id;
bool is_non_uniform;
};
class ImageOperands {
public:
[[maybe_unused]] static constexpr bool ImageSampleOffsetAllowed = false;
@ -189,8 +223,13 @@ private:
Id Texture(EmitContext& ctx, IR::TextureInstInfo info, [[maybe_unused]] const IR::Value& index) {
const TextureDefinition& def{ctx.textures.at(info.descriptor_index)};
if (def.count > 1) {
const Id pointer{ctx.OpAccessChain(def.pointer_type, def.id, ctx.Def(index))};
return ctx.OpLoad(def.sampled_type, pointer);
const DescriptorIndex idx{
ctx, index, spv::Capability::SampledImageArrayNonUniformIndexing};
const Id pointer{ctx.OpAccessChain(def.pointer_type, def.id, idx.Value())};
idx.Decorate(pointer);
const Id object{ctx.OpLoad(def.sampled_type, pointer)};
idx.Decorate(object);
return object;
} else {
return ctx.OpLoad(def.sampled_type, def.id);
}
@ -200,17 +239,25 @@ Id TextureImage(EmitContext& ctx, IR::TextureInstInfo info, const IR::Value& ind
if (info.type == TextureType::Buffer) {
const TextureBufferDefinition& def{ctx.texture_buffers.at(info.descriptor_index)};
if (def.count > 1) {
const Id idx{index.IsImmediate() ? ctx.Const(index.U32()) : ctx.Def(index)};
const Id ptr{ctx.OpAccessChain(ctx.image_buffer_type, def.id, idx)};
return ctx.OpLoad(ctx.image_buffer_type, ptr);
const DescriptorIndex idx{
ctx, index, spv::Capability::UniformTexelBufferArrayNonUniformIndexing};
const Id ptr{ctx.OpAccessChain(ctx.image_buffer_type, def.id, idx.Value())};
idx.Decorate(ptr);
const Id object{ctx.OpLoad(ctx.image_buffer_type, ptr)};
idx.Decorate(object);
return object;
}
return ctx.OpLoad(ctx.image_buffer_type, def.id);
} else {
const TextureDefinition& def{ctx.textures.at(info.descriptor_index)};
if (def.count > 1) {
const Id idx{index.IsImmediate() ? ctx.Const(index.U32()) : ctx.Def(index)};
const Id ptr{ctx.OpAccessChain(def.pointer_type, def.id, idx)};
return ctx.OpImage(def.image_type, ctx.OpLoad(def.sampled_type, ptr));
const DescriptorIndex idx{
ctx, index, spv::Capability::SampledImageArrayNonUniformIndexing};
const Id ptr{ctx.OpAccessChain(def.pointer_type, def.id, idx.Value())};
idx.Decorate(ptr);
const Id object{ctx.OpLoad(def.sampled_type, ptr)};
idx.Decorate(object);
return ctx.OpImage(def.image_type, object);
}
return ctx.OpImage(def.image_type, ctx.OpLoad(def.sampled_type, def.id));
}
@ -220,17 +267,25 @@ std::pair<Id, bool> Image(EmitContext& ctx, const IR::Value& index, IR::TextureI
if (info.type == TextureType::Buffer) {
const ImageBufferDefinition def{ctx.image_buffers.at(info.descriptor_index)};
if (def.count > 1) {
const Id idx{index.IsImmediate() ? ctx.Const(index.U32()) : ctx.Def(index)};
const Id ptr{ctx.OpAccessChain(def.pointer_type, def.id, idx)};
return {ctx.OpLoad(def.image_type, ptr), def.is_integer};
const DescriptorIndex idx{
ctx, index, spv::Capability::StorageTexelBufferArrayNonUniformIndexing};
const Id ptr{ctx.OpAccessChain(def.pointer_type, def.id, idx.Value())};
idx.Decorate(ptr);
const Id object{ctx.OpLoad(def.image_type, ptr)};
idx.Decorate(object);
return {object, def.is_integer};
}
return {ctx.OpLoad(def.image_type, def.id), def.is_integer};
} else {
const ImageDefinition def{ctx.images.at(info.descriptor_index)};
if (def.count > 1) {
const Id idx{index.IsImmediate() ? ctx.Const(index.U32()) : ctx.Def(index)};
const Id ptr{ctx.OpAccessChain(def.pointer_type, def.id, idx)};
return {ctx.OpLoad(def.image_type, ptr), def.is_integer};
const DescriptorIndex idx{
ctx, index, spv::Capability::StorageImageArrayNonUniformIndexing};
const Id ptr{ctx.OpAccessChain(def.pointer_type, def.id, idx.Value())};
idx.Decorate(ptr);
const Id object{ctx.OpLoad(def.image_type, ptr)};
idx.Decorate(object);
return {object, def.is_integer};
}
return {ctx.OpLoad(def.image_type, def.id), def.is_integer};
}

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -45,6 +48,7 @@ struct Profile {
bool support_scaled_attributes{};
bool support_multi_viewport{};
bool support_geometry_streams{};
bool support_descriptor_nonuniform_indexing{};
bool warp_size_potentially_larger_than_guest{};

View file

@ -412,6 +412,7 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
.support_scaled_attributes = !device.MustEmulateScaledFormats(),
.support_multi_viewport = device.SupportsMultiViewport(),
.support_geometry_streams = device.AreTransformFeedbackGeometryStreamsSupported(),
.support_descriptor_nonuniform_indexing = device.IsDescriptorNonUniformIndexingSupported(),
.warp_size_potentially_larger_than_guest = device.IsWarpSizePotentiallyBiggerThanGuest(),

View file

@ -33,6 +33,7 @@ VK_DEFINE_HANDLE(VmaAllocator)
FEATURE(KHR, VariablePointer, VARIABLE_POINTERS, variable_pointer)
#define FOR_EACH_VK_FEATURE_1_2(FEATURE) \
FEATURE(EXT, DescriptorIndexing, DESCRIPTOR_INDEXING, descriptor_indexing) \
FEATURE(EXT, HostQueryReset, HOST_QUERY_RESET, host_query_reset) \
FEATURE(KHR, 8BitStorage, 8BIT_STORAGE, bit8_storage) \
FEATURE(KHR, TimelineSemaphore, TIMELINE_SEMAPHORE, timeline_semaphore)
@ -355,6 +356,13 @@ public:
return GetDriverID() != VK_DRIVER_ID_QUALCOMM_PROPRIETARY;
}
bool IsDescriptorNonUniformIndexingSupported() const {
return features.descriptor_indexing.shaderSampledImageArrayNonUniformIndexing &&
features.descriptor_indexing.shaderStorageImageArrayNonUniformIndexing &&
features.descriptor_indexing.shaderUniformTexelBufferArrayNonUniformIndexing &&
features.descriptor_indexing.shaderStorageTexelBufferArrayNonUniformIndexing;
}
/// Returns true if the device supports float64 natively.
bool IsFloat64Supported() const {
return features.features.shaderFloat64;