feat(spirv): implement texture component type handling in SPIR-V backend

Update SPIR-V backend to use component-specific sampled types for
textures, ensuring correct type conversions for integer and depth/stencil
textures.

- Add ComponentScalarType helper function
- Update ImageType to accept component-specific sampled types
- Add TextureColorResultType and TextureSampleResultToFloat helpers
- Update all texture sampling functions to handle component types
- Add output_s32 for signed integer outputs
- Add Flat decorations for integer inputs in fragment shaders
- Add NonWritable decoration for read-only storage buffers

Co-Authored-By: ForrestMarkX <forrestmarkx@outlook.com>
Signed-off-by: Zephyron <zephyron@citron-emu.org>
This commit is contained in:
Zephyron
2026-01-02 17:50:00 +10:00
committed by collecting
parent decb26a766
commit eb04a096de
3 changed files with 150 additions and 43 deletions

View File

@@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <boost/container/static_vector.hpp> #include <boost/container/static_vector.hpp>
@@ -195,6 +196,41 @@ Id Texture(EmitContext& ctx, IR::TextureInstInfo info, [[maybe_unused]] const IR
} }
} }
/// Get the result type for texture color sampling based on component type
[[nodiscard]] Id TextureColorResultType(EmitContext& ctx, const TextureDefinition& def) {
switch (def.component_type) {
case SamplerComponentType::Float:
case SamplerComponentType::Depth:
return ctx.F32[4];
case SamplerComponentType::Sint:
return ctx.S32[4];
case SamplerComponentType::Stencil:
case SamplerComponentType::Uint:
return ctx.U32[4];
}
throw InvalidArgument("Invalid sampler component type {}", def.component_type);
}
/// Convert texture sample result to float, handling integer and stencil types
[[nodiscard]] Id TextureSampleResultToFloat(EmitContext& ctx, const TextureDefinition& def, Id color) {
switch (def.component_type) {
case SamplerComponentType::Float:
case SamplerComponentType::Depth:
return color;
case SamplerComponentType::Sint:
return ctx.OpConvertSToF(ctx.F32[4], color);
case SamplerComponentType::Stencil: {
const Id converted{ctx.OpConvertUToF(ctx.F32[4], color)};
const Id inv255{ctx.Const(1.0f / 255.0f)};
const Id scale{ctx.ConstantComposite(ctx.F32[4], inv255, inv255, inv255, inv255)};
return ctx.OpFMul(ctx.F32[4], converted, scale);
}
case SamplerComponentType::Uint:
return ctx.OpConvertUToF(ctx.F32[4], color);
}
throw InvalidArgument("Invalid sampler component type {}", def.component_type);
}
Id TextureImage(EmitContext& ctx, IR::TextureInstInfo info, const IR::Value& index) { Id TextureImage(EmitContext& ctx, IR::TextureInstInfo info, const IR::Value& index) {
if (!index.IsImmediate() || index.U32() != 0) { if (!index.IsImmediate() || index.U32() != 0) {
throw NotImplementedException("Indirect image indexing"); throw NotImplementedException("Indirect image indexing");
@@ -449,31 +485,39 @@ Id EmitBoundImageWrite(EmitContext&) {
Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
Id bias_lc, const IR::Value& offset) { Id bias_lc, const IR::Value& offset) {
const auto info{inst->Flags<IR::TextureInstInfo>()}; const auto info{inst->Flags<IR::TextureInstInfo>()};
const TextureDefinition& def{ctx.textures.at(info.descriptor_index)};
const Id color_type{TextureColorResultType(ctx, def)};
const Id texture{Texture(ctx, info, index)};
Id color{};
if (ctx.stage == Stage::Fragment) { if (ctx.stage == Stage::Fragment) {
const ImageOperands operands(ctx, info.has_bias != 0, false, info.has_lod_clamp != 0, const ImageOperands operands(ctx, info.has_bias != 0, false, info.has_lod_clamp != 0,
bias_lc, offset); bias_lc, offset);
return Emit(&EmitContext::OpImageSparseSampleImplicitLod, color = Emit(&EmitContext::OpImageSparseSampleImplicitLod,
&EmitContext::OpImageSampleImplicitLod, ctx, inst, ctx.F32[4], &EmitContext::OpImageSampleImplicitLod, ctx, inst, color_type, texture,
Texture(ctx, info, index), coords, operands.MaskOptional(), operands.Span()); coords, operands.MaskOptional(), operands.Span());
} else { } else {
// We can't use implicit lods on non-fragment stages on SPIR-V. Maxwell hardware behaves as // We can't use implicit lods on non-fragment stages on SPIR-V. Maxwell hardware behaves as
// if the lod was explicitly zero. This may change on Turing with implicit compute // if the lod was explicitly zero. This may change on Turing with implicit compute
// derivatives // derivatives
const Id lod{ctx.Const(0.0f)}; const Id lod{ctx.Const(0.0f)};
const ImageOperands operands(ctx, false, true, info.has_lod_clamp != 0, lod, offset); const ImageOperands operands(ctx, false, true, info.has_lod_clamp != 0, lod, offset);
return Emit(&EmitContext::OpImageSparseSampleExplicitLod, color = Emit(&EmitContext::OpImageSparseSampleExplicitLod,
&EmitContext::OpImageSampleExplicitLod, ctx, inst, ctx.F32[4], &EmitContext::OpImageSampleExplicitLod, ctx, inst, color_type, texture,
Texture(ctx, info, index), coords, operands.Mask(), operands.Span()); coords, operands.Mask(), operands.Span());
} }
return TextureSampleResultToFloat(ctx, def, color);
} }
Id EmitImageSampleExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id EmitImageSampleExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
Id lod, const IR::Value& offset) { Id lod, const IR::Value& offset) {
const auto info{inst->Flags<IR::TextureInstInfo>()}; const auto info{inst->Flags<IR::TextureInstInfo>()};
const TextureDefinition& def{ctx.textures.at(info.descriptor_index)};
const Id color_type{TextureColorResultType(ctx, def)};
const ImageOperands operands(ctx, false, true, false, lod, offset); const ImageOperands operands(ctx, false, true, false, lod, offset);
return Emit(&EmitContext::OpImageSparseSampleExplicitLod, const Id color{Emit(&EmitContext::OpImageSparseSampleExplicitLod,
&EmitContext::OpImageSampleExplicitLod, ctx, inst, ctx.F32[4], &EmitContext::OpImageSampleExplicitLod, ctx, inst, color_type,
Texture(ctx, info, index), coords, operands.Mask(), operands.Span()); Texture(ctx, info, index), coords, operands.Mask(), operands.Span())};
return TextureSampleResultToFloat(ctx, def, color);
} }
Id EmitImageSampleDrefImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id EmitImageSampleDrefImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index,
@@ -509,13 +553,18 @@ Id EmitImageSampleDrefExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Va
Id EmitImageGather(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id EmitImageGather(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
const IR::Value& offset, const IR::Value& offset2) { const IR::Value& offset, const IR::Value& offset2) {
const auto info{inst->Flags<IR::TextureInstInfo>()}; const auto info{inst->Flags<IR::TextureInstInfo>()};
const TextureDefinition& def{ctx.textures.at(info.descriptor_index)};
const Id color_type{TextureColorResultType(ctx, def)};
const ImageOperands operands(ctx, offset, offset2); const ImageOperands operands(ctx, offset, offset2);
const Id texture{Texture(ctx, info, index)};
if (ctx.profile.need_gather_subpixel_offset) { if (ctx.profile.need_gather_subpixel_offset) {
coords = ImageGatherSubpixelOffset(ctx, info, TextureImage(ctx, info, index), coords); coords = ImageGatherSubpixelOffset(ctx, info, TextureImage(ctx, info, index), coords);
} }
return Emit(&EmitContext::OpImageSparseGather, &EmitContext::OpImageGather, ctx, inst, const Id color{
ctx.F32[4], Texture(ctx, info, index), coords, ctx.Const(info.gather_component), Emit(&EmitContext::OpImageSparseGather, &EmitContext::OpImageGather, ctx, inst, color_type,
operands.MaskOptional(), operands.Span()); texture, coords, ctx.Const(info.gather_component), operands.MaskOptional(),
operands.Span())};
return TextureSampleResultToFloat(ctx, def, color);
} }
Id EmitImageGatherDref(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id EmitImageGatherDref(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
@@ -533,6 +582,9 @@ Id EmitImageGatherDref(EmitContext& ctx, IR::Inst* inst, const IR::Value& index,
Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id offset, Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id offset,
Id lod, Id ms) { Id lod, Id ms) {
const auto info{inst->Flags<IR::TextureInstInfo>()}; const auto info{inst->Flags<IR::TextureInstInfo>()};
const TextureDefinition* def =
info.type == TextureType::Buffer ? nullptr : &ctx.textures.at(info.descriptor_index);
const Id result_type{def ? TextureColorResultType(ctx, *def) : ctx.F32[4]};
AddOffsetToCoordinates(ctx, info, coords, offset); AddOffsetToCoordinates(ctx, info, coords, offset);
if (info.type == TextureType::Buffer) { if (info.type == TextureType::Buffer) {
lod = Id{}; lod = Id{};
@@ -542,8 +594,13 @@ Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id c
lod = Id{}; lod = Id{};
} }
const ImageOperands operands(lod, ms); const ImageOperands operands(lod, ms);
return Emit(&EmitContext::OpImageSparseFetch, &EmitContext::OpImageFetch, ctx, inst, ctx.F32[4], Id color{Emit(&EmitContext::OpImageSparseFetch, &EmitContext::OpImageFetch, ctx, inst,
TextureImage(ctx, info, index), coords, operands.MaskOptional(), operands.Span()); result_type, TextureImage(ctx, info, index), coords, operands.MaskOptional(),
operands.Span())};
if (def) {
color = TextureSampleResultToFloat(ctx, *def, color);
}
return color;
} }
Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod, Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod,
@@ -588,14 +645,17 @@ Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, I
Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
Id derivatives, const IR::Value& offset, Id lod_clamp) { Id derivatives, const IR::Value& offset, Id lod_clamp) {
const auto info{inst->Flags<IR::TextureInstInfo>()}; const auto info{inst->Flags<IR::TextureInstInfo>()};
const TextureDefinition& def{ctx.textures.at(info.descriptor_index)};
const Id color_type{TextureColorResultType(ctx, def)};
const auto operands = info.num_derivatives == 3 const auto operands = info.num_derivatives == 3
? ImageOperands(ctx, info.has_lod_clamp != 0, derivatives, ? ImageOperands(ctx, info.has_lod_clamp != 0, derivatives,
ctx.Def(offset), {}, lod_clamp) ctx.Def(offset), {}, lod_clamp)
: ImageOperands(ctx, info.has_lod_clamp != 0, derivatives, : ImageOperands(ctx, info.has_lod_clamp != 0, derivatives,
info.num_derivatives, offset, lod_clamp); info.num_derivatives, offset, lod_clamp);
return Emit(&EmitContext::OpImageSparseSampleExplicitLod, const Id color{Emit(&EmitContext::OpImageSparseSampleExplicitLod,
&EmitContext::OpImageSampleExplicitLod, ctx, inst, ctx.F32[4], &EmitContext::OpImageSampleExplicitLod, ctx, inst, color_type,
Texture(ctx, info, index), coords, operands.Mask(), operands.Span()); Texture(ctx, info, index), coords, operands.Mask(), operands.Span())};
return TextureSampleResultToFloat(ctx, def, color);
} }
Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords) { Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords) {

View File

@@ -26,27 +26,42 @@ enum class Operation {
FPMax, FPMax,
}; };
Id ImageType(EmitContext& ctx, const TextureDescriptor& desc) { /// Get the scalar type ID for a given sampler component type
[[nodiscard]] Id ComponentScalarType(EmitContext& ctx, SamplerComponentType component_type) {
switch (component_type) {
case SamplerComponentType::Float:
case SamplerComponentType::Depth:
return ctx.F32[1];
case SamplerComponentType::Sint:
case SamplerComponentType::Stencil:
return ctx.S32[1];
case SamplerComponentType::Uint:
return ctx.U32[1];
}
throw InvalidArgument("Invalid sampler component type {}", component_type);
}
Id ImageType(EmitContext& ctx, const TextureDescriptor& desc, Id sampled_type) {
const spv::ImageFormat format{spv::ImageFormat::Unknown}; const spv::ImageFormat format{spv::ImageFormat::Unknown};
const Id type{ctx.F32[1]}; >>>>>>> f8de99641 (feat(spirv): implement texture component type handling in SPIR-V backend)
const bool depth{desc.is_depth}; const bool depth{desc.is_depth};
const bool ms{desc.is_multisample}; const bool ms{desc.is_multisample};
switch (desc.type) { switch (desc.type) {
case TextureType::Color1D: case TextureType::Color1D:
return ctx.TypeImage(type, spv::Dim::Dim1D, depth, false, false, 1, format); return ctx.TypeImage(sampled_type, spv::Dim::Dim1D, depth, false, false, 1, format);
case TextureType::ColorArray1D: case TextureType::ColorArray1D:
return ctx.TypeImage(type, spv::Dim::Dim1D, depth, true, false, 1, format); return ctx.TypeImage(sampled_type, spv::Dim::Dim1D, depth, true, false, 1, format);
case TextureType::Color2D: case TextureType::Color2D:
case TextureType::Color2DRect: case TextureType::Color2DRect:
return ctx.TypeImage(type, spv::Dim::Dim2D, depth, false, ms, 1, format); return ctx.TypeImage(sampled_type, spv::Dim::Dim2D, depth, false, ms, 1, format);
case TextureType::ColorArray2D: case TextureType::ColorArray2D:
return ctx.TypeImage(type, spv::Dim::Dim2D, depth, true, ms, 1, format); return ctx.TypeImage(sampled_type, spv::Dim::Dim2D, depth, true, ms, 1, format);
case TextureType::Color3D: case TextureType::Color3D:
return ctx.TypeImage(type, spv::Dim::Dim3D, depth, false, false, 1, format); return ctx.TypeImage(sampled_type, spv::Dim::Dim3D, depth, false, false, 1, format);
case TextureType::ColorCube: case TextureType::ColorCube:
return ctx.TypeImage(type, spv::Dim::Cube, depth, false, false, 1, format); return ctx.TypeImage(sampled_type, spv::Dim::Cube, depth, false, false, 1, format);
case TextureType::ColorArrayCube: case TextureType::ColorArrayCube:
return ctx.TypeImage(type, spv::Dim::Cube, depth, true, false, 1, format); return ctx.TypeImage(sampled_type, spv::Dim::Cube, depth, true, false, 1, format);
case TextureType::Buffer: case TextureType::Buffer:
break; break;
} }
@@ -275,7 +290,7 @@ void Name(EmitContext& ctx, Id object, std::string_view format_str, Args&&... ar
.c_str()); .c_str());
} }
void DefineConstBuffers(EmitContext& ctx, const Info& info, Id UniformDefinitions::*member_type, void DefineConstBuffers(EmitContext& ctx, const Info& info, Id UniformDefinitions::* member_type,
u32 binding, Id type, char type_char, u32 element_size) { u32 binding, Id type, char type_char, u32 element_size) {
const Id array_type{ctx.TypeArray(type, ctx.Const(65536U / element_size))}; const Id array_type{ctx.TypeArray(type, ctx.Const(65536U / element_size))};
ctx.Decorate(array_type, spv::Decoration::ArrayStride, element_size); ctx.Decorate(array_type, spv::Decoration::ArrayStride, element_size);
@@ -306,7 +321,7 @@ void DefineConstBuffers(EmitContext& ctx, const Info& info, Id UniformDefinition
} }
void DefineSsbos(EmitContext& ctx, StorageTypeDefinition& type_def, void DefineSsbos(EmitContext& ctx, StorageTypeDefinition& type_def,
Id StorageDefinitions::*member_type, const Info& info, u32 binding, Id type, Id StorageDefinitions::* member_type, const Info& info, u32 binding, Id type,
u32 stride) { u32 stride) {
const Id array_type{ctx.TypeRuntimeArray(type)}; const Id array_type{ctx.TypeRuntimeArray(type)};
ctx.Decorate(array_type, spv::Decoration::ArrayStride, stride); ctx.Decorate(array_type, spv::Decoration::ArrayStride, stride);
@@ -325,6 +340,9 @@ void DefineSsbos(EmitContext& ctx, StorageTypeDefinition& type_def,
ctx.Decorate(id, spv::Decoration::Binding, binding); ctx.Decorate(id, spv::Decoration::Binding, binding);
ctx.Decorate(id, spv::Decoration::DescriptorSet, 0U); ctx.Decorate(id, spv::Decoration::DescriptorSet, 0U);
ctx.Name(id, fmt::format("ssbo{}", index)); ctx.Name(id, fmt::format("ssbo{}", index));
if (!desc.is_written) {
ctx.Decorate(id, spv::Decoration::NonWritable);
}
if (ctx.profile.supported_spirv >= 0x00010400) { if (ctx.profile.supported_spirv >= 0x00010400) {
ctx.interfaces.push_back(id); ctx.interfaces.push_back(id);
} }
@@ -556,6 +574,7 @@ void EmitContext::DefineCommonTypes(const Info& info) {
output_f32 = Name(TypePointer(spv::StorageClass::Output, F32[1]), "output_f32"); output_f32 = Name(TypePointer(spv::StorageClass::Output, F32[1]), "output_f32");
output_u32 = Name(TypePointer(spv::StorageClass::Output, U32[1]), "output_u32"); output_u32 = Name(TypePointer(spv::StorageClass::Output, U32[1]), "output_u32");
output_s32 = Name(TypePointer(spv::StorageClass::Output, S32[1]), "output_s32");
if (info.uses_int8 && profile.support_int8) { if (info.uses_int8 && profile.support_int8) {
AddCapability(spv::Capability::Int8); AddCapability(spv::Capability::Int8);
@@ -1169,7 +1188,7 @@ void EmitContext::DefineConstantBufferIndirectFunctions(const Info& info) {
if (!info.uses_cbuf_indirect) { if (!info.uses_cbuf_indirect) {
return; return;
} }
const auto make_accessor{[&](Id buffer_type, Id UniformDefinitions::*member_ptr) { const auto make_accessor{[&](Id buffer_type, Id UniformDefinitions::* member_ptr) {
const Id func_type{TypeFunction(buffer_type, U32[1], U32[1])}; const Id func_type{TypeFunction(buffer_type, U32[1], U32[1])};
const Id func{OpFunction(buffer_type, spv::FunctionControlMask::MaskNone, func_type)}; const Id func{OpFunction(buffer_type, spv::FunctionControlMask::MaskNone, func_type)};
const Id binding{OpFunctionParameter(U32[1])}; const Id binding{OpFunctionParameter(U32[1])};
@@ -1369,7 +1388,8 @@ void EmitContext::DefineImageBuffers(const Info& info, u32& binding) {
void EmitContext::DefineTextures(const Info& info, u32& binding, u32& scaling_index) { void EmitContext::DefineTextures(const Info& info, u32& binding, u32& scaling_index) {
textures.reserve(info.texture_descriptors.size()); textures.reserve(info.texture_descriptors.size());
for (const TextureDescriptor& desc : info.texture_descriptors) { for (const TextureDescriptor& desc : info.texture_descriptors) {
const Id image_type{ImageType(*this, desc)}; const Id result_type{ComponentScalarType(*this, desc.component_type)};
const Id image_type{ImageType(*this, desc, result_type)};
const Id sampled_type{TypeSampledImage(image_type)}; const Id sampled_type{TypeSampledImage(image_type)};
const Id pointer_type{TypePointer(spv::StorageClass::UniformConstant, sampled_type)}; const Id pointer_type{TypePointer(spv::StorageClass::UniformConstant, sampled_type)};
const Id desc_type{DescType(*this, sampled_type, pointer_type, desc.count)}; const Id desc_type{DescType(*this, sampled_type, pointer_type, desc.count)};
@@ -1382,8 +1402,11 @@ void EmitContext::DefineTextures(const Info& info, u32& binding, u32& scaling_in
.sampled_type = sampled_type, .sampled_type = sampled_type,
.pointer_type = pointer_type, .pointer_type = pointer_type,
.image_type = image_type, .image_type = image_type,
.result_type = result_type,
.count = desc.count, .count = desc.count,
.is_multisample = desc.is_multisample, .is_multisample = desc.is_multisample,
.component_type = desc.component_type,
>>>>>>> f8de99641 (feat(spirv): implement texture component type handling in SPIR-V backend)
}); });
if (profile.supported_spirv >= 0x00010400) { if (profile.supported_spirv >= 0x00010400) {
interfaces.push_back(id); interfaces.push_back(id);
@@ -1442,6 +1465,9 @@ void EmitContext::DefineInputs(const IR::Program& program) {
} }
if (info.uses_sample_id) { if (info.uses_sample_id) {
sample_id = DefineInput(*this, U32[1], false, spv::BuiltIn::SampleId); sample_id = DefineInput(*this, U32[1], false, spv::BuiltIn::SampleId);
if (stage == Stage::Fragment) {
Decorate(sample_id, spv::Decoration::Flat);
}
} }
if (info.uses_is_helper_invocation) { if (info.uses_is_helper_invocation) {
is_helper_invocation = DefineInput(*this, U1, false, spv::BuiltIn::HelperInvocation); is_helper_invocation = DefineInput(*this, U1, false, spv::BuiltIn::HelperInvocation);
@@ -1452,6 +1478,13 @@ void EmitContext::DefineInputs(const IR::Program& program) {
subgroup_mask_le = DefineInput(*this, U32[4], false, spv::BuiltIn::SubgroupLeMaskKHR); subgroup_mask_le = DefineInput(*this, U32[4], false, spv::BuiltIn::SubgroupLeMaskKHR);
subgroup_mask_gt = DefineInput(*this, U32[4], false, spv::BuiltIn::SubgroupGtMaskKHR); subgroup_mask_gt = DefineInput(*this, U32[4], false, spv::BuiltIn::SubgroupGtMaskKHR);
subgroup_mask_ge = DefineInput(*this, U32[4], false, spv::BuiltIn::SubgroupGeMaskKHR); subgroup_mask_ge = DefineInput(*this, U32[4], false, spv::BuiltIn::SubgroupGeMaskKHR);
if (stage == Stage::Fragment) {
Decorate(subgroup_mask_eq, spv::Decoration::Flat);
Decorate(subgroup_mask_lt, spv::Decoration::Flat);
Decorate(subgroup_mask_le, spv::Decoration::Flat);
Decorate(subgroup_mask_gt, spv::Decoration::Flat);
Decorate(subgroup_mask_ge, spv::Decoration::Flat);
}
} }
if (info.uses_fswzadd || info.uses_subgroup_invocation_id || info.uses_subgroup_shuffles || if (info.uses_fswzadd || info.uses_subgroup_invocation_id || info.uses_subgroup_shuffles ||
(profile.warp_size_potentially_larger_than_guest && (profile.warp_size_potentially_larger_than_guest &&
@@ -1459,7 +1492,9 @@ void EmitContext::DefineInputs(const IR::Program& program) {
AddCapability(spv::Capability::GroupNonUniform); AddCapability(spv::Capability::GroupNonUniform);
subgroup_local_invocation_id = subgroup_local_invocation_id =
DefineInput(*this, U32[1], false, spv::BuiltIn::SubgroupLocalInvocationId); DefineInput(*this, U32[1], false, spv::BuiltIn::SubgroupLocalInvocationId);
Decorate(subgroup_local_invocation_id, spv::Decoration::Flat); if (stage == Stage::Fragment) {
Decorate(subgroup_local_invocation_id, spv::Decoration::Flat);
}
} }
if (info.uses_fswzadd) { if (info.uses_fswzadd) {
const Id f32_one{Const(1.0f)}; const Id f32_one{Const(1.0f)};
@@ -1471,6 +1506,9 @@ void EmitContext::DefineInputs(const IR::Program& program) {
} }
if (loads[IR::Attribute::PrimitiveId]) { if (loads[IR::Attribute::PrimitiveId]) {
primitive_id = DefineInput(*this, U32[1], false, spv::BuiltIn::PrimitiveId); primitive_id = DefineInput(*this, U32[1], false, spv::BuiltIn::PrimitiveId);
if (stage == Stage::Fragment) {
Decorate(primitive_id, spv::Decoration::Flat);
}
} }
if (loads[IR::Attribute::Layer]) { if (loads[IR::Attribute::Layer]) {
AddCapability(spv::Capability::Geometry); AddCapability(spv::Capability::Geometry);
@@ -1562,17 +1600,23 @@ void EmitContext::DefineInputs(const IR::Program& program) {
if (stage != Stage::Fragment) { if (stage != Stage::Fragment) {
continue; continue;
} }
switch (info.interpolation[index]) { const bool is_integer =
case Interpolation::Smooth: input_type == AttributeType::SignedInt || input_type == AttributeType::UnsignedInt;
// Default if (is_integer) {
// Decorate(id, spv::Decoration::Smooth);
break;
case Interpolation::NoPerspective:
Decorate(id, spv::Decoration::NoPerspective);
break;
case Interpolation::Flat:
Decorate(id, spv::Decoration::Flat); Decorate(id, spv::Decoration::Flat);
break; } else {
switch (info.interpolation[index]) {
case Interpolation::Smooth:
// Default
// Decorate(id, spv::Decoration::Smooth);
break;
case Interpolation::NoPerspective:
Decorate(id, spv::Decoration::NoPerspective);
break;
case Interpolation::Flat:
Decorate(id, spv::Decoration::Flat);
break;
}
} }
} }
if (stage == Stage::TessellationEval) { if (stage == Stage::TessellationEval) {

View File

@@ -34,8 +34,10 @@ struct TextureDefinition {
Id sampled_type; Id sampled_type;
Id pointer_type; Id pointer_type;
Id image_type; Id image_type;
Id result_type;
u32 count; u32 count;
bool is_multisample; bool is_multisample;
SamplerComponentType component_type;
}; };
struct TextureBufferDefinition { struct TextureBufferDefinition {
@@ -67,7 +69,7 @@ struct UniformDefinitions {
Id U32x2{}; Id U32x2{};
Id U32x4{}; Id U32x4{};
constexpr static size_t NumElements(Id UniformDefinitions::*member_ptr) { constexpr static size_t NumElements(Id UniformDefinitions::* member_ptr) {
if (member_ptr == &UniformDefinitions::U8) { if (member_ptr == &UniformDefinitions::U8) {
return 1; return 1;
} }
@@ -96,7 +98,7 @@ struct UniformDefinitions {
return 1; return 1;
} }
constexpr static bool IsFloat(Id UniformDefinitions::*member_ptr) { constexpr static bool IsFloat(Id UniformDefinitions::* member_ptr) {
if (member_ptr == &UniformDefinitions::F32) { if (member_ptr == &UniformDefinitions::F32) {
return true; return true;
} }
@@ -242,6 +244,7 @@ public:
Id output_f32{}; Id output_f32{};
Id output_u32{}; Id output_u32{};
Id output_s32{};
Id image_buffer_type{}; Id image_buffer_type{};
Id image_u32{}; Id image_u32{};