early-access version 3625
This commit is contained in:
@@ -69,11 +69,6 @@ Id StorageAtomicU32(EmitContext& ctx, const IR::Value& binding, const IR::Value&
|
||||
Id StorageAtomicU64(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, Id value,
|
||||
Id (Sirit::Module::*atomic_func)(Id, Id, Id, Id, Id),
|
||||
Id (Sirit::Module::*non_atomic_func)(Id, Id, Id)) {
|
||||
if (!ctx.profile.support_descriptor_aliasing) {
|
||||
LOG_WARNING(Shader_SPIRV, "Descriptor aliasing not supported, this cannot be atomic.");
|
||||
return ctx.ConstantNull(ctx.U64);
|
||||
}
|
||||
|
||||
if (ctx.profile.support_int64_atomics) {
|
||||
const Id pointer{StoragePointer(ctx, ctx.storage_types.U64, &StorageDefinitions::U64,
|
||||
binding, offset, sizeof(u64))};
|
||||
@@ -91,11 +86,6 @@ Id StorageAtomicU64(EmitContext& ctx, const IR::Value& binding, const IR::Value&
|
||||
|
||||
Id StorageAtomicU32x2(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, Id value,
|
||||
Id (Sirit::Module::*non_atomic_func)(Id, Id, Id)) {
|
||||
if (!ctx.profile.support_descriptor_aliasing) {
|
||||
LOG_WARNING(Shader_SPIRV, "Descriptor aliasing not supported, this cannot be atomic.");
|
||||
return ctx.ConstantNull(ctx.U32[2]);
|
||||
}
|
||||
|
||||
LOG_WARNING(Shader_SPIRV, "Int64 atomics not supported, fallback to non-atomic");
|
||||
const Id pointer{StoragePointer(ctx, ctx.storage_types.U32x2, &StorageDefinitions::U32x2,
|
||||
binding, offset, sizeof(u32[2]))};
|
||||
|
@@ -10,6 +10,27 @@
|
||||
|
||||
namespace Shader::Backend::SPIRV {
|
||||
namespace {
|
||||
struct AttrInfo {
|
||||
Id pointer;
|
||||
Id id;
|
||||
bool needs_cast;
|
||||
};
|
||||
|
||||
std::optional<AttrInfo> AttrTypes(EmitContext& ctx, u32 index) {
|
||||
const AttributeType type{ctx.runtime_info.generic_input_types.at(index)};
|
||||
switch (type) {
|
||||
case AttributeType::Float:
|
||||
return AttrInfo{ctx.input_f32, ctx.F32[1], false};
|
||||
case AttributeType::UnsignedInt:
|
||||
return AttrInfo{ctx.input_u32, ctx.U32[1], true};
|
||||
case AttributeType::SignedInt:
|
||||
return AttrInfo{ctx.input_s32, ctx.TypeInt(32, true), true};
|
||||
case AttributeType::Disabled:
|
||||
return std::nullopt;
|
||||
}
|
||||
throw InvalidArgument("Invalid attribute type {}", type);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
Id AttrPointer(EmitContext& ctx, Id pointer_type, Id vertex, Id base, Args&&... args) {
|
||||
switch (ctx.stage) {
|
||||
@@ -281,26 +302,15 @@ Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex) {
|
||||
const u32 element{static_cast<u32>(attr) % 4};
|
||||
if (IR::IsGeneric(attr)) {
|
||||
const u32 index{IR::GenericAttributeIndex(attr)};
|
||||
const auto& generic{ctx.input_generics.at(index)};
|
||||
if (!ValidId(generic.id)) {
|
||||
const std::optional<AttrInfo> type{AttrTypes(ctx, index)};
|
||||
if (!type || !ctx.runtime_info.previous_stage_stores.Generic(index, element)) {
|
||||
// Attribute is disabled or varying component is not written
|
||||
return ctx.Const(element == 3 ? 1.0f : 0.0f);
|
||||
}
|
||||
const Id pointer{
|
||||
AttrPointer(ctx, generic.pointer_type, vertex, generic.id, ctx.Const(element))};
|
||||
const Id value{ctx.OpLoad(generic.component_type, pointer)};
|
||||
return [&ctx, generic, value]() {
|
||||
switch (generic.load_op) {
|
||||
case InputGenericLoadOp::Bitcast:
|
||||
return ctx.OpBitcast(ctx.F32[1], value);
|
||||
case InputGenericLoadOp::SToF:
|
||||
return ctx.OpConvertSToF(ctx.F32[1], value);
|
||||
case InputGenericLoadOp::UToF:
|
||||
return ctx.OpConvertUToF(ctx.F32[1], value);
|
||||
default:
|
||||
return value;
|
||||
};
|
||||
}();
|
||||
const Id generic_id{ctx.input_generics.at(index)};
|
||||
const Id pointer{AttrPointer(ctx, type->pointer, vertex, generic_id, ctx.Const(element))};
|
||||
const Id value{ctx.OpLoad(type->id, pointer)};
|
||||
return type->needs_cast ? ctx.OpBitcast(ctx.F32[1], value) : value;
|
||||
}
|
||||
switch (attr) {
|
||||
case IR::Attribute::PrimitiveId:
|
||||
|
@@ -17,22 +17,7 @@ Id GetThreadId(EmitContext& ctx) {
|
||||
Id WarpExtract(EmitContext& ctx, Id value) {
|
||||
const Id thread_id{GetThreadId(ctx)};
|
||||
const Id local_index{ctx.OpShiftRightArithmetic(ctx.U32[1], thread_id, ctx.Const(5U))};
|
||||
if (ctx.profile.has_broken_spirv_subgroup_mask_vector_extract_dynamic) {
|
||||
const Id c0_sel{ctx.OpSelect(ctx.U32[1], ctx.OpIEqual(ctx.U1, local_index, ctx.Const(0U)),
|
||||
ctx.OpCompositeExtract(ctx.U32[1], value, 0U), ctx.Const(0U))};
|
||||
const Id c1_sel{ctx.OpSelect(ctx.U32[1], ctx.OpIEqual(ctx.U1, local_index, ctx.Const(1U)),
|
||||
ctx.OpCompositeExtract(ctx.U32[1], value, 1U), ctx.Const(0U))};
|
||||
const Id c2_sel{ctx.OpSelect(ctx.U32[1], ctx.OpIEqual(ctx.U1, local_index, ctx.Const(2U)),
|
||||
ctx.OpCompositeExtract(ctx.U32[1], value, 2U), ctx.Const(0U))};
|
||||
const Id c3_sel{ctx.OpSelect(ctx.U32[1], ctx.OpIEqual(ctx.U1, local_index, ctx.Const(3U)),
|
||||
ctx.OpCompositeExtract(ctx.U32[1], value, 3U), ctx.Const(0U))};
|
||||
const Id c0_or_c1{ctx.OpBitwiseOr(ctx.U32[1], c0_sel, c1_sel)};
|
||||
const Id c2_or_c3{ctx.OpBitwiseOr(ctx.U32[1], c2_sel, c3_sel)};
|
||||
const Id c0_or_c1_or_c2_or_c3{ctx.OpBitwiseOr(ctx.U32[1], c0_or_c1, c2_or_c3)};
|
||||
return c0_or_c1_or_c2_or_c3;
|
||||
} else {
|
||||
return ctx.OpVectorExtractDynamic(ctx.U32[1], value, local_index);
|
||||
}
|
||||
return ctx.OpVectorExtractDynamic(ctx.U32[1], value, local_index);
|
||||
}
|
||||
|
||||
Id LoadMask(EmitContext& ctx, Id mask) {
|
||||
|
@@ -25,6 +25,12 @@ enum class Operation {
|
||||
FPMax,
|
||||
};
|
||||
|
||||
struct AttrInfo {
|
||||
Id pointer;
|
||||
Id id;
|
||||
bool needs_cast;
|
||||
};
|
||||
|
||||
Id ImageType(EmitContext& ctx, const TextureDescriptor& desc) {
|
||||
const spv::ImageFormat format{spv::ImageFormat::Unknown};
|
||||
const Id type{ctx.F32[1]};
|
||||
@@ -200,37 +206,23 @@ Id GetAttributeType(EmitContext& ctx, AttributeType type) {
|
||||
return ctx.TypeVector(ctx.TypeInt(32, true), 4);
|
||||
case AttributeType::UnsignedInt:
|
||||
return ctx.U32[4];
|
||||
case AttributeType::SignedScaled:
|
||||
return ctx.profile.support_scaled_attributes ? ctx.F32[4]
|
||||
: ctx.TypeVector(ctx.TypeInt(32, true), 4);
|
||||
case AttributeType::UnsignedScaled:
|
||||
return ctx.profile.support_scaled_attributes ? ctx.F32[4] : ctx.U32[4];
|
||||
case AttributeType::Disabled:
|
||||
break;
|
||||
}
|
||||
throw InvalidArgument("Invalid attribute type {}", type);
|
||||
}
|
||||
|
||||
InputGenericInfo GetAttributeInfo(EmitContext& ctx, AttributeType type, Id id) {
|
||||
std::optional<AttrInfo> AttrTypes(EmitContext& ctx, u32 index) {
|
||||
const AttributeType type{ctx.runtime_info.generic_input_types.at(index)};
|
||||
switch (type) {
|
||||
case AttributeType::Float:
|
||||
return InputGenericInfo{id, ctx.input_f32, ctx.F32[1], InputGenericLoadOp::None};
|
||||
return AttrInfo{ctx.input_f32, ctx.F32[1], false};
|
||||
case AttributeType::UnsignedInt:
|
||||
return InputGenericInfo{id, ctx.input_u32, ctx.U32[1], InputGenericLoadOp::Bitcast};
|
||||
return AttrInfo{ctx.input_u32, ctx.U32[1], true};
|
||||
case AttributeType::SignedInt:
|
||||
return InputGenericInfo{id, ctx.input_s32, ctx.TypeInt(32, true),
|
||||
InputGenericLoadOp::Bitcast};
|
||||
case AttributeType::SignedScaled:
|
||||
return ctx.profile.support_scaled_attributes
|
||||
? InputGenericInfo{id, ctx.input_f32, ctx.F32[1], InputGenericLoadOp::None}
|
||||
: InputGenericInfo{id, ctx.input_s32, ctx.TypeInt(32, true),
|
||||
InputGenericLoadOp::SToF};
|
||||
case AttributeType::UnsignedScaled:
|
||||
return ctx.profile.support_scaled_attributes
|
||||
? InputGenericInfo{id, ctx.input_f32, ctx.F32[1], InputGenericLoadOp::None}
|
||||
: InputGenericInfo{id, ctx.input_u32, ctx.U32[1], InputGenericLoadOp::UToF};
|
||||
return AttrInfo{ctx.input_s32, ctx.TypeInt(32, true), true};
|
||||
case AttributeType::Disabled:
|
||||
return InputGenericInfo{};
|
||||
return std::nullopt;
|
||||
}
|
||||
throw InvalidArgument("Invalid attribute type {}", type);
|
||||
}
|
||||
@@ -754,29 +746,18 @@ void EmitContext::DefineAttributeMemAccess(const Info& info) {
|
||||
continue;
|
||||
}
|
||||
AddLabel(labels[label_index]);
|
||||
const auto& generic{input_generics.at(index)};
|
||||
const Id generic_id{generic.id};
|
||||
if (!ValidId(generic_id)) {
|
||||
const auto type{AttrTypes(*this, static_cast<u32>(index))};
|
||||
if (!type) {
|
||||
OpReturnValue(Const(0.0f));
|
||||
++label_index;
|
||||
continue;
|
||||
}
|
||||
const Id pointer{
|
||||
is_array ? OpAccessChain(generic.pointer_type, generic_id, vertex, masked_index)
|
||||
: OpAccessChain(generic.pointer_type, generic_id, masked_index)};
|
||||
const Id value{OpLoad(generic.component_type, pointer)};
|
||||
const Id result{[this, generic, value]() {
|
||||
switch (generic.load_op) {
|
||||
case InputGenericLoadOp::Bitcast:
|
||||
return OpBitcast(F32[1], value);
|
||||
case InputGenericLoadOp::SToF:
|
||||
return OpConvertSToF(F32[1], value);
|
||||
case InputGenericLoadOp::UToF:
|
||||
return OpConvertUToF(F32[1], value);
|
||||
default:
|
||||
return value;
|
||||
};
|
||||
}()};
|
||||
const Id generic_id{input_generics.at(index)};
|
||||
const Id pointer{is_array
|
||||
? OpAccessChain(type->pointer, generic_id, vertex, masked_index)
|
||||
: OpAccessChain(type->pointer, generic_id, masked_index)};
|
||||
const Id value{OpLoad(type->id, pointer)};
|
||||
const Id result{type->needs_cast ? OpBitcast(F32[1], value) : value};
|
||||
OpReturnValue(result);
|
||||
++label_index;
|
||||
}
|
||||
@@ -1476,7 +1457,7 @@ void EmitContext::DefineInputs(const IR::Program& program) {
|
||||
const Id id{DefineInput(*this, type, true)};
|
||||
Decorate(id, spv::Decoration::Location, static_cast<u32>(index));
|
||||
Name(id, fmt::format("in_attr{}", index));
|
||||
input_generics[index] = GetAttributeInfo(*this, input_type, id);
|
||||
input_generics[index] = id;
|
||||
|
||||
if (info.passthrough.Generic(index) && profile.support_geometry_shader_passthrough) {
|
||||
Decorate(id, spv::Decoration::PassthroughNV);
|
||||
|
@@ -95,20 +95,6 @@ struct StorageDefinitions {
|
||||
Id U32x4{};
|
||||
};
|
||||
|
||||
enum class InputGenericLoadOp {
|
||||
None,
|
||||
Bitcast,
|
||||
SToF,
|
||||
UToF,
|
||||
};
|
||||
|
||||
struct InputGenericInfo {
|
||||
Id id;
|
||||
Id pointer_type;
|
||||
Id component_type;
|
||||
InputGenericLoadOp load_op;
|
||||
};
|
||||
|
||||
struct GenericElementInfo {
|
||||
Id id{};
|
||||
u32 first_element{};
|
||||
@@ -297,7 +283,7 @@ public:
|
||||
|
||||
bool need_input_position_indirect{};
|
||||
Id input_position{};
|
||||
std::array<InputGenericInfo, 32> input_generics{};
|
||||
std::array<Id, 32> input_generics{};
|
||||
|
||||
Id output_point_size{};
|
||||
Id output_position{};
|
||||
|
@@ -43,7 +43,6 @@ struct Profile {
|
||||
bool support_gl_variable_aoffi{};
|
||||
bool support_gl_sparse_textures{};
|
||||
bool support_gl_derivative_control{};
|
||||
bool support_scaled_attributes{};
|
||||
|
||||
bool warp_size_potentially_larger_than_guest{};
|
||||
|
||||
@@ -78,8 +77,6 @@ struct Profile {
|
||||
bool has_gl_bool_ref_bug{};
|
||||
/// Ignores SPIR-V ordered vs unordered using GLSL semantics
|
||||
bool ignore_nan_fp_comparisons{};
|
||||
/// Some drivers have broken support for OpVectorExtractDynamic on subgroup mask inputs
|
||||
bool has_broken_spirv_subgroup_mask_vector_extract_dynamic{};
|
||||
|
||||
u32 gl_max_compute_smem_size{};
|
||||
};
|
||||
|
@@ -17,8 +17,6 @@ enum class AttributeType : u8 {
|
||||
Float,
|
||||
SignedInt,
|
||||
UnsignedInt,
|
||||
SignedScaled,
|
||||
UnsignedScaled,
|
||||
Disabled,
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user