Vulkan: Add a workaround for input_position on Adreno drivers

Adreno drivers will crash compiling geometry shaders if the input position is not wrapped in a gl_in struct.
This commit is contained in:
Billy Laws 2022-08-02 17:41:41 +01:00
parent 1428451722
commit bbfad79c89
5 changed files with 42 additions and 11 deletions

View File

@ -321,7 +321,10 @@ Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex) {
case IR::Attribute::PositionY: case IR::Attribute::PositionY:
case IR::Attribute::PositionZ: case IR::Attribute::PositionZ:
case IR::Attribute::PositionW: case IR::Attribute::PositionW:
return ctx.OpLoad(ctx.F32[1], AttrPointer(ctx, ctx.input_f32, vertex, ctx.input_position, return ctx.OpLoad(ctx.F32[1], ctx.need_input_position_indirect ?
AttrPointer(ctx, ctx.input_f32, vertex, ctx.input_position,
ctx.u32_zero_value, ctx.Const(element))
: AttrPointer(ctx, ctx.input_f32, vertex, ctx.input_position,
ctx.Const(element))); ctx.Const(element)));
case IR::Attribute::InstanceId: case IR::Attribute::InstanceId:
if (ctx.profile.support_vertex_instance_id) { if (ctx.profile.support_vertex_instance_id) {

View File

@ -721,9 +721,21 @@ void EmitContext::DefineAttributeMemAccess(const Info& info) {
size_t label_index{0}; size_t label_index{0};
if (info.loads.AnyComponent(IR::Attribute::PositionX)) { if (info.loads.AnyComponent(IR::Attribute::PositionX)) {
AddLabel(labels[label_index]); AddLabel(labels[label_index]);
const Id pointer{is_array const Id pointer{[&]() {
? OpAccessChain(input_f32, input_position, vertex, masked_index) if (need_input_position_indirect) {
: OpAccessChain(input_f32, input_position, masked_index)}; if (is_array)
return OpAccessChain(input_f32, input_position, vertex, u32_zero_value,
masked_index);
else
return OpAccessChain(input_f32, input_position, u32_zero_value,
masked_index);
} else {
if (is_array)
return OpAccessChain(input_f32, input_position, vertex, masked_index);
else
return OpAccessChain(input_f32, input_position, masked_index);
}
}()};
const Id result{OpLoad(F32[1], pointer)}; const Id result{OpLoad(F32[1], pointer)};
OpReturnValue(result); OpReturnValue(result);
++label_index; ++label_index;
@ -1367,15 +1379,27 @@ void EmitContext::DefineInputs(const IR::Program& program) {
Decorate(layer, spv::Decoration::Flat); Decorate(layer, spv::Decoration::Flat);
} }
if (loads.AnyComponent(IR::Attribute::PositionX)) { if (loads.AnyComponent(IR::Attribute::PositionX)) {
const bool is_fragment{stage != Stage::Fragment}; const bool is_fragment{stage == Stage::Fragment};
const spv::BuiltIn built_in{is_fragment ? spv::BuiltIn::Position : spv::BuiltIn::FragCoord}; if (!is_fragment && profile.has_broken_spirv_position_input) {
need_input_position_indirect = true;
const Id input_position_struct = TypeStruct(F32[4]);
input_position = DefineInput(*this, input_position_struct, true);
MemberDecorate(input_position_struct, 0, spv::Decoration::BuiltIn,
static_cast<unsigned>(spv::BuiltIn::Position));
Decorate(input_position_struct, spv::Decoration::Block);
} else {
const spv::BuiltIn built_in{is_fragment ? spv::BuiltIn::FragCoord : spv::BuiltIn::Position};
input_position = DefineInput(*this, F32[4], true, built_in); input_position = DefineInput(*this, F32[4], true, built_in);
if (profile.support_geometry_shader_passthrough) { if (profile.support_geometry_shader_passthrough) {
if (info.passthrough.AnyComponent(IR::Attribute::PositionX)) { if (info.passthrough.AnyComponent(IR::Attribute::PositionX)) {
Decorate(input_position, spv::Decoration::PassthroughNV); Decorate(input_position, spv::Decoration::PassthroughNV);
} }
} }
} }
}
if (loads[IR::Attribute::InstanceId]) { if (loads[IR::Attribute::InstanceId]) {
if (profile.support_vertex_instance_id) { if (profile.support_vertex_instance_id) {
instance_id = DefineInput(*this, U32[1], true, spv::BuiltIn::InstanceId); instance_id = DefineInput(*this, U32[1], true, spv::BuiltIn::InstanceId);

View File

@ -280,6 +280,7 @@ public:
Id write_global_func_u32x2{}; Id write_global_func_u32x2{};
Id write_global_func_u32x4{}; Id write_global_func_u32x4{};
bool need_input_position_indirect{};
Id input_position{}; Id input_position{};
std::array<Id, 32> input_generics{}; std::array<Id, 32> input_generics{};

View File

@ -55,6 +55,8 @@ struct Profile {
/// OpFClamp is broken and OpFMax + OpFMin should be used instead /// OpFClamp is broken and OpFMax + OpFMin should be used instead
bool has_broken_spirv_clamp{}; bool has_broken_spirv_clamp{};
/// The Position builtin needs to be wrapped in a struct when used as an input
bool has_broken_spirv_position_input{};
/// Offset image operands with an unsigned type do not work /// Offset image operands with an unsigned type do not work
bool has_broken_unsigned_image_offsets{}; bool has_broken_unsigned_image_offsets{};
/// Signed instructions with unsigned data types are misinterpreted /// Signed instructions with unsigned data types are misinterpreted

View File

@ -331,6 +331,7 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device
.need_declared_frag_colors = false, .need_declared_frag_colors = false,
.has_broken_spirv_clamp = driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS, .has_broken_spirv_clamp = driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS,
.has_broken_spirv_position_input = driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY,
.has_broken_unsigned_image_offsets = false, .has_broken_unsigned_image_offsets = false,
.has_broken_signed_operations = false, .has_broken_signed_operations = false,
.has_broken_fp16_float_controls = driver_id == VK_DRIVER_ID_NVIDIA_PROPRIETARY, .has_broken_fp16_float_controls = driver_id == VK_DRIVER_ID_NVIDIA_PROPRIETARY,