mirror of
https://git.eden-emu.dev/archive/citron
synced 2026-04-13 08:10:47 -04:00
feat(shader): implement texture component type handling in SPIR-V backend
- Add ComponentScalarType helper function - Update ImageType to use component-specific sampled types - Add TextureColorResultType and TextureSampleResultToFloat helpers - Update all texture sampling functions to handle component types correctly - Add proper type conversions for integer and stencil textures - Add Flat decorations for integer inputs in fragment shaders - Add NonWritable decoration for read-only storage buffers This ensures textures are sampled with the correct component types, improving accuracy for integer and depth/stencil textures. Co-Authored-By: ForrestMarkX <forrestmarkx@outlook.com> Signed-off-by: Zephyron <zephyron@citron-emu.org>
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 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
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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:
|
||||||
|
return ctx.U32[4];
|
||||||
|
case SamplerComponentType::Uint:
|
||||||
|
return ctx.U32[4];
|
||||||
|
}
|
||||||
|
throw InvalidArgument("Invalid sampler component type {}", def.component_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
|||||||
@@ -26,28 +26,40 @@ enum class Operation {
|
|||||||
FPMax,
|
FPMax,
|
||||||
};
|
};
|
||||||
|
|
||||||
Id ImageType(EmitContext& ctx, const TextureDescriptor& desc) {
|
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};
|
||||||
// Use integer type for integer textures to match the actual texture format
|
|
||||||
const Id type{desc.is_integer ? ctx.U32[1] : ctx.F32[1]};
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
@@ -326,6 +338,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);
|
||||||
}
|
}
|
||||||
@@ -557,6 +572,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);
|
||||||
@@ -1370,7 +1386,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)};
|
||||||
@@ -1383,9 +1400,10 @@ 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,
|
||||||
.is_integer = desc.is_integer,
|
.component_type = desc.component_type,
|
||||||
});
|
});
|
||||||
if (profile.supported_spirv >= 0x00010400) {
|
if (profile.supported_spirv >= 0x00010400) {
|
||||||
interfaces.push_back(id);
|
interfaces.push_back(id);
|
||||||
@@ -1444,6 +1462,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);
|
||||||
@@ -1454,6 +1475,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 &&
|
||||||
@@ -1461,7 +1489,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)};
|
||||||
@@ -1473,6 +1503,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);
|
||||||
@@ -1564,17 +1597,21 @@ 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 = input_type == AttributeType::SignedInt ||
|
||||||
case Interpolation::Smooth:
|
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:
|
||||||
|
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) {
|
||||||
|
|||||||
@@ -35,9 +35,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;
|
||||||
bool is_integer;
|
SamplerComponentType component_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TextureBufferDefinition {
|
struct TextureBufferDefinition {
|
||||||
@@ -244,6 +245,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{};
|
||||||
|
|||||||
Reference in New Issue
Block a user