mirror of
https://git.eden-emu.dev/eden-emu/eden
synced 2026-04-22 05:48:59 +02:00
Controlled SPV features on QCOM
This commit is contained in:
parent
f40774a4b9
commit
d6f14f5519
6 changed files with 418 additions and 88 deletions
|
|
@ -13,23 +13,26 @@
|
|||
|
||||
#include <fmt/ranges.h>
|
||||
|
||||
#include "common/common_types.h"
|
||||
const Id vec_type{ctx.F32[4]};
|
||||
#include "common/div_ceil.h"
|
||||
#include "shader_recompiler/backend/spirv/emit_spirv.h"
|
||||
#include "shader_recompiler/backend/spirv/spirv_emit_context.h"
|
||||
|
||||
namespace Shader::Backend::SPIRV {
|
||||
vec_type,
|
||||
ctx.TypePointer(spv::StorageClass::Input, vec_type),
|
||||
namespace {
|
||||
enum class Operation {
|
||||
Increment,
|
||||
const Id vec_type{ctx.U32[4]};
|
||||
Decrement,
|
||||
FPAdd,
|
||||
FPMin,
|
||||
FPMax,
|
||||
};
|
||||
vec_type,
|
||||
ctx.TypePointer(spv::StorageClass::Input, vec_type),
|
||||
|
||||
Id ImageType(EmitContext& ctx, const TextureDescriptor& desc) {
|
||||
const spv::ImageFormat format{spv::ImageFormat::Unknown};
|
||||
const Id scalar_type{ctx.TypeInt(32, true)};
|
||||
const Id vec_type{ctx.TypeVector(scalar_type, 4)};
|
||||
const Id type{ctx.F32[1]};
|
||||
const bool depth{desc.is_depth};
|
||||
const bool ms{desc.is_multisample};
|
||||
|
|
@ -39,35 +42,39 @@ Id ImageType(EmitContext& ctx, const TextureDescriptor& desc) {
|
|||
case TextureType::ColorArray1D:
|
||||
return ctx.TypeImage(type, spv::Dim::Dim1D, depth, true, false, 1, format);
|
||||
case TextureType::Color2D:
|
||||
const Id vec_type{ctx.F32[4]};
|
||||
case TextureType::Color2DRect:
|
||||
return ctx.TypeImage(type, spv::Dim::Dim2D, depth, false, ms, 1, format);
|
||||
case TextureType::ColorArray2D:
|
||||
return ctx.TypeImage(type, spv::Dim::Dim2D, depth, true, ms, 1, format);
|
||||
case TextureType::Color3D:
|
||||
vec_type,
|
||||
ctx.TypePointer(spv::StorageClass::Input, vec_type),
|
||||
return ctx.TypeImage(type, spv::Dim::Dim3D, depth, false, false, 1, format);
|
||||
case TextureType::ColorCube:
|
||||
return ctx.TypeImage(type, spv::Dim::Cube, depth, false, false, 1, format);
|
||||
case TextureType::ColorArrayCube:
|
||||
return ctx.TypeImage(type, spv::Dim::Cube, depth, true, false, 1, format);
|
||||
case TextureType::Buffer:
|
||||
break;
|
||||
}
|
||||
throw InvalidArgument("Invalid texture type {}", desc.type);
|
||||
const Id scalar_type{ctx.TypeInt(32, true)};
|
||||
const Id vec_type{ctx.TypeVector(scalar_type, 4)};
|
||||
return InputGenericInfo{id,
|
||||
ctx.input_s32,
|
||||
scalar_type,
|
||||
vec_type,
|
||||
ctx.TypePointer(spv::StorageClass::Input, vec_type),
|
||||
InputGenericLoadOp::SToF};
|
||||
}
|
||||
|
||||
const Id vec_type{ctx.F32[4]};
|
||||
spv::ImageFormat GetImageFormat(ImageFormat format) {
|
||||
switch (format) {
|
||||
case ImageFormat::Typeless:
|
||||
return spv::ImageFormat::Unknown;
|
||||
case ImageFormat::R8_UINT:
|
||||
vec_type,
|
||||
ctx.TypePointer(spv::StorageClass::Input, vec_type),
|
||||
return spv::ImageFormat::R8ui;
|
||||
case ImageFormat::R8_SINT:
|
||||
return spv::ImageFormat::R8i;
|
||||
case ImageFormat::R16_UINT:
|
||||
return spv::ImageFormat::R16ui;
|
||||
case ImageFormat::R16_SINT:
|
||||
return spv::ImageFormat::R16i;
|
||||
case ImageFormat::R32_UINT:
|
||||
const Id vec_type{ctx.U32[4]};
|
||||
return InputGenericInfo{id,
|
||||
ctx.input_u32,
|
||||
ctx.U32[1],
|
||||
vec_type,
|
||||
ctx.TypePointer(spv::StorageClass::Input, vec_type),
|
||||
InputGenericLoadOp::UToF};
|
||||
return spv::ImageFormat::R32ui;
|
||||
case ImageFormat::R32G32_UINT:
|
||||
return spv::ImageFormat::Rg32ui;
|
||||
|
|
@ -185,10 +192,14 @@ void DefineGenericOutput(EmitContext& ctx, size_t index, std::optional<u32> invo
|
|||
} else {
|
||||
ctx.Name(id, fmt::format("out_attr{}", index));
|
||||
}
|
||||
const Id vector_type{ctx.F32[num_components]};
|
||||
const GenericElementInfo info{
|
||||
.id = id,
|
||||
.first_element = element,
|
||||
.num_components = num_components,
|
||||
.composite_type = vector_type,
|
||||
.composite_pointer_type =
|
||||
ctx.TypePointer(spv::StorageClass::Output, vector_type),
|
||||
};
|
||||
std::fill_n(ctx.output_generics[index].begin() + element, num_components, info);
|
||||
element += num_components;
|
||||
|
|
@ -217,21 +228,58 @@ Id GetAttributeType(EmitContext& ctx, AttributeType type) {
|
|||
InputGenericInfo GetAttributeInfo(EmitContext& ctx, AttributeType type, Id id) {
|
||||
switch (type) {
|
||||
case AttributeType::Float:
|
||||
return InputGenericInfo{id, ctx.input_f32, ctx.F32[1], InputGenericLoadOp::None};
|
||||
return InputGenericInfo{id,
|
||||
ctx.input_f32,
|
||||
ctx.F32[1],
|
||||
ctx.F32[4],
|
||||
ctx.TypePointer(spv::StorageClass::Input, ctx.F32[4]),
|
||||
InputGenericLoadOp::None};
|
||||
case AttributeType::UnsignedInt:
|
||||
return InputGenericInfo{id, ctx.input_u32, ctx.U32[1], InputGenericLoadOp::Bitcast};
|
||||
return InputGenericInfo{id,
|
||||
ctx.input_u32,
|
||||
ctx.U32[1],
|
||||
ctx.U32[4],
|
||||
ctx.TypePointer(spv::StorageClass::Input, ctx.U32[4]),
|
||||
InputGenericLoadOp::Bitcast};
|
||||
case AttributeType::SignedInt:
|
||||
return InputGenericInfo{id, ctx.input_s32, ctx.TypeInt(32, true),
|
||||
return InputGenericInfo{id,
|
||||
ctx.input_s32,
|
||||
ctx.TypeInt(32, true),
|
||||
ctx.TypeVector(ctx.TypeInt(32, true), 4),
|
||||
ctx.TypePointer(spv::StorageClass::Input,
|
||||
ctx.TypeVector(ctx.TypeInt(32, true), 4)),
|
||||
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};
|
||||
if (ctx.profile.support_scaled_attributes) {
|
||||
return InputGenericInfo{id,
|
||||
ctx.input_f32,
|
||||
ctx.F32[1],
|
||||
ctx.F32[4],
|
||||
ctx.TypePointer(spv::StorageClass::Input, ctx.F32[4]),
|
||||
InputGenericLoadOp::None};
|
||||
}
|
||||
return InputGenericInfo{id,
|
||||
ctx.input_s32,
|
||||
ctx.TypeInt(32, true),
|
||||
ctx.TypeVector(ctx.TypeInt(32, true), 4),
|
||||
ctx.TypePointer(spv::StorageClass::Input,
|
||||
ctx.TypeVector(ctx.TypeInt(32, true), 4)),
|
||||
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};
|
||||
if (ctx.profile.support_scaled_attributes) {
|
||||
return InputGenericInfo{id,
|
||||
ctx.input_f32,
|
||||
ctx.F32[1],
|
||||
ctx.F32[4],
|
||||
ctx.TypePointer(spv::StorageClass::Input, ctx.F32[4]),
|
||||
InputGenericLoadOp::None};
|
||||
}
|
||||
return InputGenericInfo{id,
|
||||
ctx.input_u32,
|
||||
ctx.U32[1],
|
||||
ctx.U32[4],
|
||||
ctx.TypePointer(spv::StorageClass::Input, ctx.U32[4]),
|
||||
InputGenericLoadOp::UToF};
|
||||
case AttributeType::Disabled:
|
||||
return InputGenericInfo{};
|
||||
}
|
||||
|
|
@ -702,7 +750,8 @@ void EmitContext::DefineSharedMemoryFunctions(const IR::Program& program) {
|
|||
|
||||
void EmitContext::DefineAttributeMemAccess(const Info& info) {
|
||||
const auto make_load{[&] {
|
||||
const bool is_array{stage == Stage::Geometry};
|
||||
const bool is_array{stage == Stage::Geometry || stage == Stage::TessellationControl ||
|
||||
stage == Stage::TessellationEval};
|
||||
const Id end_block{OpLabel()};
|
||||
const Id default_label{OpLabel()};
|
||||
|
||||
|
|
@ -737,6 +786,28 @@ void EmitContext::DefineAttributeMemAccess(const Info& info) {
|
|||
size_t label_index{0};
|
||||
if (info.loads.AnyComponent(IR::Attribute::PositionX)) {
|
||||
AddLabel(labels[label_index]);
|
||||
if (ctx.profile.has_broken_spirv_vector_access_chain) {
|
||||
const Id pointer_type{TypePointer(spv::StorageClass::Input, F32[4])};
|
||||
const Id vector_pointer{[&]() {
|
||||
if (need_input_position_indirect) {
|
||||
if (is_array) {
|
||||
return OpAccessChain(pointer_type, input_position, vertex,
|
||||
u32_zero_value);
|
||||
}
|
||||
return OpAccessChain(pointer_type, input_position, u32_zero_value);
|
||||
} else {
|
||||
if (is_array) {
|
||||
return OpAccessChain(pointer_type, input_position, vertex);
|
||||
}
|
||||
return input_position;
|
||||
}
|
||||
}()};
|
||||
const Id vector_value{OpLoad(F32[4], vector_pointer)};
|
||||
const Id result{OpVectorExtractDynamic(F32[1], vector_value, masked_index)};
|
||||
OpReturnValue(result);
|
||||
++label_index;
|
||||
continue;
|
||||
}
|
||||
const Id pointer{[&]() {
|
||||
if (need_input_position_indirect) {
|
||||
if (is_array)
|
||||
|
|
@ -768,22 +839,36 @@ void EmitContext::DefineAttributeMemAccess(const Info& info) {
|
|||
++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]() {
|
||||
const auto convert_value{[&](Id component) {
|
||||
switch (generic.load_op) {
|
||||
case InputGenericLoadOp::Bitcast:
|
||||
return OpBitcast(F32[1], value);
|
||||
return OpBitcast(F32[1], component);
|
||||
case InputGenericLoadOp::SToF:
|
||||
return OpConvertSToF(F32[1], value);
|
||||
return OpConvertSToF(F32[1], component);
|
||||
case InputGenericLoadOp::UToF:
|
||||
return OpConvertUToF(F32[1], value);
|
||||
return OpConvertUToF(F32[1], component);
|
||||
default:
|
||||
return value;
|
||||
};
|
||||
}()};
|
||||
return component;
|
||||
}
|
||||
}};
|
||||
Id result{};
|
||||
if (ctx.profile.has_broken_spirv_vector_access_chain) {
|
||||
const Id vector_pointer{is_array
|
||||
? OpAccessChain(generic.composite_pointer_type,
|
||||
generic_id, vertex)
|
||||
: generic_id};
|
||||
const Id vector_value{OpLoad(generic.composite_type, vector_pointer)};
|
||||
const Id component_value{
|
||||
OpVectorExtractDynamic(generic.component_type, vector_value, masked_index)};
|
||||
result = convert_value(component_value);
|
||||
} else {
|
||||
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)};
|
||||
result = convert_value(value);
|
||||
}
|
||||
OpReturnValue(result);
|
||||
++label_index;
|
||||
}
|
||||
|
|
@ -835,6 +920,19 @@ void EmitContext::DefineAttributeMemAccess(const Info& info) {
|
|||
size_t label_index{0};
|
||||
if (info.stores.AnyComponent(IR::Attribute::PositionX)) {
|
||||
AddLabel(labels[label_index]);
|
||||
if (ctx.profile.has_broken_spirv_vector_access_chain) {
|
||||
const bool use_invocation{ctx.stage == Stage::TessellationControl};
|
||||
const Id pointer_type{TypePointer(spv::StorageClass::Output, F32[4])};
|
||||
const Id vector_pointer{use_invocation
|
||||
? OpAccessChain(pointer_type, output_position,
|
||||
OpLoad(U32[1], invocation_id))
|
||||
: output_position};
|
||||
const Id vector_value{OpLoad(F32[4], vector_pointer)};
|
||||
const Id updated{
|
||||
OpVectorInsertDynamic(F32[4], vector_value, store_value, masked_index)};
|
||||
OpStore(vector_pointer, updated);
|
||||
OpReturn();
|
||||
}
|
||||
const Id pointer{OpAccessChain(output_f32, output_position, masked_index)};
|
||||
OpStore(pointer, store_value);
|
||||
OpReturn();
|
||||
|
|
@ -848,7 +946,27 @@ void EmitContext::DefineAttributeMemAccess(const Info& info) {
|
|||
throw NotImplementedException("Physical stores and transform feedbacks");
|
||||
}
|
||||
AddLabel(labels[label_index]);
|
||||
const Id generic_id{output_generics[index][0].id};
|
||||
const GenericElementInfo& element_info{output_generics[index][0]};
|
||||
if (ctx.profile.has_broken_spirv_vector_access_chain) {
|
||||
Id local_index{masked_index};
|
||||
if (element_info.first_element != 0) {
|
||||
local_index = OpISub(U32[1], masked_index, Const(element_info.first_element));
|
||||
}
|
||||
const bool use_invocation{ctx.stage == Stage::TessellationControl};
|
||||
const Id pointer_type{
|
||||
TypePointer(spv::StorageClass::Output, element_info.composite_type)};
|
||||
const Id invocation{use_invocation ? OpLoad(U32[1], invocation_id) : Id{}};
|
||||
const Id vector_pointer{use_invocation
|
||||
? OpAccessChain(pointer_type, element_info.id,
|
||||
invocation)
|
||||
: element_info.id};
|
||||
const Id vector_value{OpLoad(element_info.composite_type, vector_pointer)};
|
||||
const Id updated{OpVectorInsertDynamic(element_info.composite_type, vector_value,
|
||||
store_value, local_index)};
|
||||
OpStore(vector_pointer, updated);
|
||||
OpReturn();
|
||||
}
|
||||
const Id generic_id{element_info.id};
|
||||
const Id pointer{OpAccessChain(output_f32, generic_id, masked_index)};
|
||||
OpStore(pointer, store_value);
|
||||
OpReturn();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue