shader: Split profile and runtime information in separate structs
This commit is contained in:
parent
eb15667905
commit
9e7b6622c2
@ -23,23 +23,25 @@ std::string_view InterpDecorator(Interpolation interp) {
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile& profile_)
|
||||
: info{program.info}, profile{profile_} {
|
||||
EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile& profile_,
|
||||
const RuntimeInfo& runtime_info_)
|
||||
: profile{profile_}, runtime_info{runtime_info_} {
|
||||
// FIXME: Temporary partial implementation
|
||||
const auto& info{program.info};
|
||||
u32 cbuf_index{};
|
||||
for (const auto& desc : program.info.constant_buffer_descriptors) {
|
||||
for (const auto& desc : info.constant_buffer_descriptors) {
|
||||
if (desc.count != 1) {
|
||||
throw NotImplementedException("Constant buffer descriptor array");
|
||||
}
|
||||
Add("CBUFFER c{}[]={{program.buffer[{}]}};", desc.index, cbuf_index);
|
||||
++cbuf_index;
|
||||
}
|
||||
for (const auto& desc : program.info.storage_buffers_descriptors) {
|
||||
for (const auto& desc : info.storage_buffers_descriptors) {
|
||||
if (desc.count != 1) {
|
||||
throw NotImplementedException("Storage buffer descriptor array");
|
||||
}
|
||||
}
|
||||
if (const size_t num = program.info.storage_buffers_descriptors.size(); num > 0) {
|
||||
if (const size_t num = info.storage_buffers_descriptors.size(); num > 0) {
|
||||
Add("PARAM c[{}]={{program.local[0..{}]}};", num, num - 1);
|
||||
}
|
||||
stage = program.stage;
|
||||
@ -67,8 +69,8 @@ EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile
|
||||
break;
|
||||
}
|
||||
const std::string_view attr_stage{stage == Stage::Fragment ? "fragment" : "vertex"};
|
||||
for (size_t index = 0; index < program.info.input_generics.size(); ++index) {
|
||||
const auto& generic{program.info.input_generics[index]};
|
||||
for (size_t index = 0; index < info.input_generics.size(); ++index) {
|
||||
const auto& generic{info.input_generics[index]};
|
||||
if (generic.used) {
|
||||
Add("{}ATTRIB in_attr{}[]={{{}.attrib[{}..{}]}};",
|
||||
InterpDecorator(generic.interpolation), index, attr_stage, index, index);
|
||||
@ -101,8 +103,8 @@ EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile
|
||||
index, index);
|
||||
}
|
||||
}
|
||||
for (size_t index = 0; index < program.info.stores_frag_color.size(); ++index) {
|
||||
if (!program.info.stores_frag_color[index]) {
|
||||
for (size_t index = 0; index < info.stores_frag_color.size(); ++index) {
|
||||
if (!info.stores_frag_color[index]) {
|
||||
continue;
|
||||
}
|
||||
if (index == 0) {
|
||||
@ -111,28 +113,28 @@ EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile
|
||||
Add("OUTPUT frag_color{}=result.color[{}];", index, index);
|
||||
}
|
||||
}
|
||||
for (size_t index = 0; index < program.info.stores_generics.size(); ++index) {
|
||||
if (program.info.stores_generics[index]) {
|
||||
for (size_t index = 0; index < info.stores_generics.size(); ++index) {
|
||||
if (info.stores_generics[index]) {
|
||||
Add("OUTPUT out_attr{}[]={{result.attrib[{}..{}]}};", index, index, index);
|
||||
}
|
||||
}
|
||||
image_buffer_bindings.reserve(program.info.image_buffer_descriptors.size());
|
||||
for (const auto& desc : program.info.image_buffer_descriptors) {
|
||||
image_buffer_bindings.reserve(info.image_buffer_descriptors.size());
|
||||
for (const auto& desc : info.image_buffer_descriptors) {
|
||||
image_buffer_bindings.push_back(bindings.image);
|
||||
bindings.image += desc.count;
|
||||
}
|
||||
image_bindings.reserve(program.info.image_descriptors.size());
|
||||
for (const auto& desc : program.info.image_descriptors) {
|
||||
image_bindings.reserve(info.image_descriptors.size());
|
||||
for (const auto& desc : info.image_descriptors) {
|
||||
image_bindings.push_back(bindings.image);
|
||||
bindings.image += desc.count;
|
||||
}
|
||||
texture_buffer_bindings.reserve(program.info.texture_buffer_descriptors.size());
|
||||
for (const auto& desc : program.info.texture_buffer_descriptors) {
|
||||
texture_buffer_bindings.reserve(info.texture_buffer_descriptors.size());
|
||||
for (const auto& desc : info.texture_buffer_descriptors) {
|
||||
texture_buffer_bindings.push_back(bindings.texture);
|
||||
bindings.texture += desc.count;
|
||||
}
|
||||
texture_bindings.reserve(program.info.texture_descriptors.size());
|
||||
for (const auto& desc : program.info.texture_descriptors) {
|
||||
texture_bindings.reserve(info.texture_descriptors.size());
|
||||
for (const auto& desc : info.texture_descriptors) {
|
||||
texture_bindings.push_back(bindings.texture);
|
||||
bindings.texture += desc.count;
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
namespace Shader {
|
||||
struct Info;
|
||||
struct Profile;
|
||||
struct RuntimeInfo;
|
||||
} // namespace Shader
|
||||
|
||||
namespace Shader::Backend {
|
||||
@ -31,7 +32,8 @@ namespace Shader::Backend::GLASM {
|
||||
|
||||
class EmitContext {
|
||||
public:
|
||||
explicit EmitContext(IR::Program& program, Bindings& bindings, const Profile& profile_);
|
||||
explicit EmitContext(IR::Program& program, Bindings& bindings, const Profile& profile_,
|
||||
const RuntimeInfo& runtime_info_);
|
||||
|
||||
template <typename... Args>
|
||||
void Add(const char* format_str, IR::Inst& inst, Args&&... args) {
|
||||
@ -56,8 +58,8 @@ public:
|
||||
|
||||
std::string code;
|
||||
RegAlloc reg_alloc{*this};
|
||||
const Info& info;
|
||||
const Profile& profile;
|
||||
const RuntimeInfo& runtime_info;
|
||||
|
||||
std::vector<u32> texture_buffer_bindings;
|
||||
std::vector<u32> image_buffer_bindings;
|
||||
|
@ -374,8 +374,9 @@ std::string_view GetTessSpacing(TessSpacing spacing) {
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
std::string EmitGLASM(const Profile& profile, IR::Program& program, Bindings& bindings) {
|
||||
EmitContext ctx{program, bindings, profile};
|
||||
std::string EmitGLASM(const Profile& profile, const RuntimeInfo& runtime_info, IR::Program& program,
|
||||
Bindings& bindings) {
|
||||
EmitContext ctx{program, bindings, profile, runtime_info};
|
||||
Precolor(ctx, program);
|
||||
EmitCode(ctx, program);
|
||||
std::string header{StageHeader(program.stage)};
|
||||
@ -385,18 +386,18 @@ std::string EmitGLASM(const Profile& profile, IR::Program& program, Bindings& bi
|
||||
header += fmt::format("VERTICES_OUT {};", program.invocations);
|
||||
break;
|
||||
case Stage::TessellationEval:
|
||||
header +=
|
||||
fmt::format("TESS_MODE {};"
|
||||
header += fmt::format("TESS_MODE {};"
|
||||
"TESS_SPACING {};"
|
||||
"TESS_VERTEX_ORDER {};",
|
||||
GetTessMode(profile.tess_primitive), GetTessSpacing(profile.tess_spacing),
|
||||
profile.tess_clockwise ? "CW" : "CCW");
|
||||
GetTessMode(runtime_info.tess_primitive),
|
||||
GetTessSpacing(runtime_info.tess_spacing),
|
||||
runtime_info.tess_clockwise ? "CW" : "CCW");
|
||||
break;
|
||||
case Stage::Geometry:
|
||||
header += fmt::format("PRIMITIVE_IN {};"
|
||||
"PRIMITIVE_OUT {};"
|
||||
"VERTICES_OUT {};",
|
||||
InputPrimitive(profile.input_topology),
|
||||
InputPrimitive(runtime_info.input_topology),
|
||||
OutputPrimitive(program.output_topology), program.output_vertices);
|
||||
break;
|
||||
case Stage::Compute:
|
||||
|
@ -12,12 +12,12 @@
|
||||
|
||||
namespace Shader::Backend::GLASM {
|
||||
|
||||
[[nodiscard]] std::string EmitGLASM(const Profile& profile, IR::Program& program,
|
||||
Bindings& binding);
|
||||
[[nodiscard]] std::string EmitGLASM(const Profile& profile, const RuntimeInfo& runtime_info,
|
||||
IR::Program& program, Bindings& bindings);
|
||||
|
||||
[[nodiscard]] inline std::string EmitGLASM(const Profile& profile, IR::Program& program) {
|
||||
Bindings binding;
|
||||
return EmitGLASM(profile, program, binding);
|
||||
return EmitGLASM(profile, {}, program, binding);
|
||||
}
|
||||
|
||||
} // namespace Shader::Backend::GLASM
|
||||
|
@ -136,7 +136,7 @@ Id DefineInput(EmitContext& ctx, Id type, bool per_invocation,
|
||||
break;
|
||||
case Stage::Geometry:
|
||||
if (per_invocation) {
|
||||
const u32 num_vertices{NumVertices(ctx.profile.input_topology)};
|
||||
const u32 num_vertices{NumVertices(ctx.runtime_info.input_topology)};
|
||||
type = ctx.TypeArray(type, ctx.Const(num_vertices));
|
||||
}
|
||||
break;
|
||||
@ -161,8 +161,8 @@ void DefineGenericOutput(EmitContext& ctx, size_t index, std::optional<u32> invo
|
||||
while (element < 4) {
|
||||
const u32 remainder{4 - element};
|
||||
const TransformFeedbackVarying* xfb_varying{};
|
||||
if (!ctx.profile.xfb_varyings.empty()) {
|
||||
xfb_varying = &ctx.profile.xfb_varyings[base_attr_index + element];
|
||||
if (!ctx.runtime_info.xfb_varyings.empty()) {
|
||||
xfb_varying = &ctx.runtime_info.xfb_varyings[base_attr_index + element];
|
||||
xfb_varying = xfb_varying && xfb_varying->components > 0 ? xfb_varying : nullptr;
|
||||
}
|
||||
const u32 num_components{xfb_varying ? xfb_varying->components : remainder};
|
||||
@ -208,7 +208,7 @@ Id GetAttributeType(EmitContext& ctx, AttributeType type) {
|
||||
}
|
||||
|
||||
std::optional<AttrInfo> AttrTypes(EmitContext& ctx, u32 index) {
|
||||
const AttributeType type{ctx.profile.generic_input_types.at(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};
|
||||
@ -441,13 +441,15 @@ void VectorTypes::Define(Sirit::Module& sirit_ctx, Id base_type, std::string_vie
|
||||
}
|
||||
}
|
||||
|
||||
EmitContext::EmitContext(const Profile& profile_, IR::Program& program, Bindings& binding)
|
||||
: Sirit::Module(profile_.supported_spirv), profile{profile_}, stage{program.stage} {
|
||||
EmitContext::EmitContext(const Profile& profile_, const RuntimeInfo& runtime_info_,
|
||||
IR::Program& program, Bindings& bindings)
|
||||
: Sirit::Module(profile_.supported_spirv), profile{profile_},
|
||||
runtime_info{runtime_info_}, stage{program.stage} {
|
||||
const bool is_unified{profile.unified_descriptor_binding};
|
||||
u32& uniform_binding{is_unified ? binding.unified : binding.uniform_buffer};
|
||||
u32& storage_binding{is_unified ? binding.unified : binding.storage_buffer};
|
||||
u32& texture_binding{is_unified ? binding.unified : binding.texture};
|
||||
u32& image_binding{is_unified ? binding.unified : binding.image};
|
||||
u32& uniform_binding{is_unified ? bindings.unified : bindings.uniform_buffer};
|
||||
u32& storage_binding{is_unified ? bindings.unified : bindings.storage_buffer};
|
||||
u32& texture_binding{is_unified ? bindings.unified : bindings.texture};
|
||||
u32& image_binding{is_unified ? bindings.unified : bindings.image};
|
||||
AddCapability(spv::Capability::Shader);
|
||||
DefineCommonTypes(program.info);
|
||||
DefineCommonConstants();
|
||||
@ -1211,7 +1213,7 @@ void EmitContext::DefineInputs(const Info& info) {
|
||||
if (!generic.used) {
|
||||
continue;
|
||||
}
|
||||
const AttributeType input_type{profile.generic_input_types[index]};
|
||||
const AttributeType input_type{runtime_info.generic_input_types[index]};
|
||||
if (input_type == AttributeType::Disabled) {
|
||||
continue;
|
||||
}
|
||||
@ -1256,7 +1258,7 @@ void EmitContext::DefineOutputs(const IR::Program& program) {
|
||||
if (info.stores_position || stage == Stage::VertexB) {
|
||||
output_position = DefineOutput(*this, F32[4], invocations, spv::BuiltIn::Position);
|
||||
}
|
||||
if (info.stores_point_size || profile.fixed_state_point_size) {
|
||||
if (info.stores_point_size || runtime_info.fixed_state_point_size) {
|
||||
if (stage == Stage::Fragment) {
|
||||
throw NotImplementedException("Storing PointSize in fragment stage");
|
||||
}
|
||||
|
@ -103,7 +103,8 @@ struct GenericElementInfo {
|
||||
|
||||
class EmitContext final : public Sirit::Module {
|
||||
public:
|
||||
explicit EmitContext(const Profile& profile, IR::Program& program, Bindings& binding);
|
||||
explicit EmitContext(const Profile& profile, const RuntimeInfo& runtime_info,
|
||||
IR::Program& program, Bindings& binding);
|
||||
~EmitContext();
|
||||
|
||||
[[nodiscard]] Id Def(const IR::Value& value);
|
||||
@ -150,6 +151,7 @@ public:
|
||||
}
|
||||
|
||||
const Profile& profile;
|
||||
const RuntimeInfo& runtime_info;
|
||||
Stage stage{};
|
||||
|
||||
Id void_id{};
|
||||
|
@ -226,16 +226,17 @@ void DefineEntryPoint(const IR::Program& program, EmitContext& ctx, Id main) {
|
||||
case Stage::TessellationEval:
|
||||
execution_model = spv::ExecutionModel::TessellationEvaluation;
|
||||
ctx.AddCapability(spv::Capability::Tessellation);
|
||||
ctx.AddExecutionMode(main, ExecutionMode(ctx.profile.tess_primitive));
|
||||
ctx.AddExecutionMode(main, ExecutionMode(ctx.profile.tess_spacing));
|
||||
ctx.AddExecutionMode(main, ctx.profile.tess_clockwise ? spv::ExecutionMode::VertexOrderCw
|
||||
ctx.AddExecutionMode(main, ExecutionMode(ctx.runtime_info.tess_primitive));
|
||||
ctx.AddExecutionMode(main, ExecutionMode(ctx.runtime_info.tess_spacing));
|
||||
ctx.AddExecutionMode(main, ctx.runtime_info.tess_clockwise
|
||||
? spv::ExecutionMode::VertexOrderCw
|
||||
: spv::ExecutionMode::VertexOrderCcw);
|
||||
break;
|
||||
case Stage::Geometry:
|
||||
execution_model = spv::ExecutionModel::Geometry;
|
||||
ctx.AddCapability(spv::Capability::Geometry);
|
||||
ctx.AddCapability(spv::Capability::GeometryStreams);
|
||||
switch (ctx.profile.input_topology) {
|
||||
switch (ctx.runtime_info.input_topology) {
|
||||
case InputTopology::Points:
|
||||
ctx.AddExecutionMode(main, spv::ExecutionMode::InputPoints);
|
||||
break;
|
||||
@ -279,7 +280,7 @@ void DefineEntryPoint(const IR::Program& program, EmitContext& ctx, Id main) {
|
||||
if (program.info.stores_frag_depth) {
|
||||
ctx.AddExecutionMode(main, spv::ExecutionMode::DepthReplacing);
|
||||
}
|
||||
if (ctx.profile.force_early_z) {
|
||||
if (ctx.runtime_info.force_early_z) {
|
||||
ctx.AddExecutionMode(main, spv::ExecutionMode::EarlyFragmentTests);
|
||||
}
|
||||
break;
|
||||
@ -402,7 +403,7 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct
|
||||
if (info.uses_sample_id) {
|
||||
ctx.AddCapability(spv::Capability::SampleRateShading);
|
||||
}
|
||||
if (!ctx.profile.xfb_varyings.empty()) {
|
||||
if (!ctx.runtime_info.xfb_varyings.empty()) {
|
||||
ctx.AddCapability(spv::Capability::TransformFeedback);
|
||||
}
|
||||
if (info.uses_derivatives) {
|
||||
@ -433,8 +434,9 @@ void PatchPhiNodes(IR::Program& program, EmitContext& ctx) {
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
std::vector<u32> EmitSPIRV(const Profile& profile, IR::Program& program, Bindings& binding) {
|
||||
EmitContext ctx{profile, program, binding};
|
||||
std::vector<u32> EmitSPIRV(const Profile& profile, const RuntimeInfo& runtime_info,
|
||||
IR::Program& program, Bindings& bindings) {
|
||||
EmitContext ctx{profile, runtime_info, program, bindings};
|
||||
const Id main{DefineMain(ctx, program)};
|
||||
DefineEntryPoint(program, ctx, main);
|
||||
if (profile.support_float_controls) {
|
||||
|
@ -16,12 +16,12 @@
|
||||
|
||||
namespace Shader::Backend::SPIRV {
|
||||
|
||||
[[nodiscard]] std::vector<u32> EmitSPIRV(const Profile& profile, IR::Program& program,
|
||||
Bindings& binding);
|
||||
[[nodiscard]] std::vector<u32> EmitSPIRV(const Profile& profile, const RuntimeInfo& runtime_info,
|
||||
IR::Program& program, Bindings& bindings);
|
||||
|
||||
[[nodiscard]] inline std::vector<u32> EmitSPIRV(const Profile& profile, IR::Program& program) {
|
||||
Bindings binding;
|
||||
return EmitSPIRV(profile, program, binding);
|
||||
return EmitSPIRV(profile, {}, program, binding);
|
||||
}
|
||||
|
||||
} // namespace Shader::Backend::SPIRV
|
||||
|
@ -17,7 +17,7 @@ struct AttrInfo {
|
||||
};
|
||||
|
||||
std::optional<AttrInfo> AttrTypes(EmitContext& ctx, u32 index) {
|
||||
const AttributeType type{ctx.profile.generic_input_types.at(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};
|
||||
@ -468,7 +468,7 @@ Id EmitIsHelperInvocation(EmitContext& ctx) {
|
||||
}
|
||||
|
||||
Id EmitYDirection(EmitContext& ctx) {
|
||||
return ctx.Const(ctx.profile.y_negate ? -1.0f : 1.0f);
|
||||
return ctx.Const(ctx.runtime_info.y_negate ? -1.0f : 1.0f);
|
||||
}
|
||||
|
||||
Id EmitLoadLocal(EmitContext& ctx, Id word_offset) {
|
||||
|
@ -18,8 +18,8 @@ void ConvertDepthMode(EmitContext& ctx) {
|
||||
}
|
||||
|
||||
void SetFixedPipelinePointSize(EmitContext& ctx) {
|
||||
if (ctx.profile.fixed_state_point_size) {
|
||||
const float point_size{*ctx.profile.fixed_state_point_size};
|
||||
if (ctx.runtime_info.fixed_state_point_size) {
|
||||
const float point_size{*ctx.runtime_info.fixed_state_point_size};
|
||||
ctx.OpStore(ctx.output_point_size, ctx.Const(point_size));
|
||||
}
|
||||
}
|
||||
@ -62,7 +62,10 @@ Id ComparisonFunction(EmitContext& ctx, CompareFunction comparison, Id operand_1
|
||||
}
|
||||
|
||||
void AlphaTest(EmitContext& ctx) {
|
||||
const auto comparison{*ctx.profile.alpha_test_func};
|
||||
if (!ctx.runtime_info.alpha_test_func) {
|
||||
return;
|
||||
}
|
||||
const auto comparison{*ctx.runtime_info.alpha_test_func};
|
||||
if (comparison == CompareFunction::Always) {
|
||||
return;
|
||||
}
|
||||
@ -76,7 +79,7 @@ void AlphaTest(EmitContext& ctx) {
|
||||
|
||||
const Id true_label{ctx.OpLabel()};
|
||||
const Id discard_label{ctx.OpLabel()};
|
||||
const Id alpha_reference{ctx.Const(ctx.profile.alpha_test_reference)};
|
||||
const Id alpha_reference{ctx.Const(ctx.runtime_info.alpha_test_reference)};
|
||||
const Id condition{ComparisonFunction(ctx, comparison, alpha, alpha_reference)};
|
||||
|
||||
ctx.OpSelectionMerge(true_label, spv::SelectionControlMask::MaskNone);
|
||||
@ -113,7 +116,7 @@ void EmitPrologue(EmitContext& ctx) {
|
||||
}
|
||||
|
||||
void EmitEpilogue(EmitContext& ctx) {
|
||||
if (ctx.stage == Stage::VertexB && ctx.profile.convert_depth_mode) {
|
||||
if (ctx.stage == Stage::VertexB && ctx.runtime_info.convert_depth_mode) {
|
||||
ConvertDepthMode(ctx);
|
||||
}
|
||||
if (ctx.stage == Stage::Fragment) {
|
||||
@ -122,7 +125,7 @@ void EmitEpilogue(EmitContext& ctx) {
|
||||
}
|
||||
|
||||
void EmitEmitVertex(EmitContext& ctx, const IR::Value& stream) {
|
||||
if (ctx.profile.convert_depth_mode) {
|
||||
if (ctx.runtime_info.convert_depth_mode) {
|
||||
ConvertDepthMode(ctx);
|
||||
}
|
||||
if (stream.IsImmediate()) {
|
||||
|
@ -81,19 +81,22 @@ struct Profile {
|
||||
bool support_viewport_mask{};
|
||||
bool support_typeless_image_loads{};
|
||||
bool support_demote_to_helper_invocation{};
|
||||
bool warp_size_potentially_larger_than_guest{};
|
||||
bool support_int64_atomics{};
|
||||
|
||||
bool warp_size_potentially_larger_than_guest{};
|
||||
bool lower_left_origin_mode{};
|
||||
|
||||
// FClamp is broken and OpFMax + OpFMin should be used instead
|
||||
/// OpFClamp is broken and OpFMax + OpFMin should be used instead
|
||||
bool has_broken_spirv_clamp{};
|
||||
// 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{};
|
||||
// Signed instructions with unsigned data types are misinterpreted
|
||||
/// Signed instructions with unsigned data types are misinterpreted
|
||||
bool has_broken_signed_operations{};
|
||||
// Ignores SPIR-V ordered vs unordered using GLSL semantics
|
||||
/// Ignores SPIR-V ordered vs unordered using GLSL semantics
|
||||
bool ignore_nan_fp_comparisons{};
|
||||
};
|
||||
|
||||
struct RuntimeInfo {
|
||||
std::array<AttributeType, 32> generic_input_types{};
|
||||
bool convert_depth_mode{};
|
||||
bool force_early_z{};
|
||||
|
@ -61,33 +61,15 @@ const Shader::Profile profile{
|
||||
.support_viewport_mask = true,
|
||||
.support_typeless_image_loads = true,
|
||||
.support_demote_to_helper_invocation = false,
|
||||
.warp_size_potentially_larger_than_guest = true,
|
||||
.support_int64_atomics = false,
|
||||
|
||||
.warp_size_potentially_larger_than_guest = true,
|
||||
.lower_left_origin_mode = true,
|
||||
|
||||
.has_broken_spirv_clamp = true,
|
||||
.has_broken_unsigned_image_offsets = true,
|
||||
.has_broken_signed_operations = true,
|
||||
.ignore_nan_fp_comparisons = true,
|
||||
|
||||
.generic_input_types = {},
|
||||
.convert_depth_mode = false,
|
||||
.force_early_z = false,
|
||||
|
||||
.tess_primitive = {},
|
||||
.tess_spacing = {},
|
||||
.tess_clockwise = false,
|
||||
|
||||
.input_topology = Shader::InputTopology::Triangles,
|
||||
|
||||
.fixed_state_point_size = std::nullopt,
|
||||
|
||||
.alpha_test_func = Shader::CompareFunction::Always,
|
||||
.alpha_test_reference = 0.0f,
|
||||
|
||||
.y_negate = false,
|
||||
|
||||
.xfb_varyings = {},
|
||||
};
|
||||
|
||||
using Shader::Backend::GLASM::EmitGLASM;
|
||||
@ -302,10 +284,10 @@ std::unique_ptr<GraphicsProgram> ShaderCache::CreateGraphicsProgram(
|
||||
const size_t stage_index{index - 1};
|
||||
infos[stage_index] = &program.info;
|
||||
if (device.UseAssemblyShaders()) {
|
||||
const std::string code{EmitGLASM(profile, program, binding)};
|
||||
const std::string code{EmitGLASM(profile, {}, program, binding)};
|
||||
assembly_programs[stage_index] = CompileProgram(code, AssemblyStage(stage_index));
|
||||
} else {
|
||||
const std::vector<u32> code{EmitSPIRV(profile, program, binding)};
|
||||
const std::vector<u32> code{EmitSPIRV(profile, {}, program, binding)};
|
||||
AddShader(Stage(stage_index), source_program.handle, code);
|
||||
}
|
||||
}
|
||||
|
@ -89,6 +89,208 @@ Shader::CompareFunction MaxwellToCompareFunction(Maxwell::ComparisonOp compariso
|
||||
UNIMPLEMENTED_MSG("Unimplemented comparison op={}", comparison);
|
||||
return {};
|
||||
}
|
||||
|
||||
static Shader::AttributeType CastAttributeType(const FixedPipelineState::VertexAttribute& attr) {
|
||||
if (attr.enabled == 0) {
|
||||
return Shader::AttributeType::Disabled;
|
||||
}
|
||||
switch (attr.Type()) {
|
||||
case Maxwell::VertexAttribute::Type::SignedNorm:
|
||||
case Maxwell::VertexAttribute::Type::UnsignedNorm:
|
||||
case Maxwell::VertexAttribute::Type::UnsignedScaled:
|
||||
case Maxwell::VertexAttribute::Type::SignedScaled:
|
||||
case Maxwell::VertexAttribute::Type::Float:
|
||||
return Shader::AttributeType::Float;
|
||||
case Maxwell::VertexAttribute::Type::SignedInt:
|
||||
return Shader::AttributeType::SignedInt;
|
||||
case Maxwell::VertexAttribute::Type::UnsignedInt:
|
||||
return Shader::AttributeType::UnsignedInt;
|
||||
}
|
||||
return Shader::AttributeType::Float;
|
||||
}
|
||||
|
||||
std::vector<Shader::TransformFeedbackVarying> MakeTransformFeedbackVaryings(
|
||||
const GraphicsPipelineCacheKey& key) {
|
||||
static constexpr std::array VECTORS{
|
||||
28, // gl_Position
|
||||
32, // Generic 0
|
||||
36, // Generic 1
|
||||
40, // Generic 2
|
||||
44, // Generic 3
|
||||
48, // Generic 4
|
||||
52, // Generic 5
|
||||
56, // Generic 6
|
||||
60, // Generic 7
|
||||
64, // Generic 8
|
||||
68, // Generic 9
|
||||
72, // Generic 10
|
||||
76, // Generic 11
|
||||
80, // Generic 12
|
||||
84, // Generic 13
|
||||
88, // Generic 14
|
||||
92, // Generic 15
|
||||
96, // Generic 16
|
||||
100, // Generic 17
|
||||
104, // Generic 18
|
||||
108, // Generic 19
|
||||
112, // Generic 20
|
||||
116, // Generic 21
|
||||
120, // Generic 22
|
||||
124, // Generic 23
|
||||
128, // Generic 24
|
||||
132, // Generic 25
|
||||
136, // Generic 26
|
||||
140, // Generic 27
|
||||
144, // Generic 28
|
||||
148, // Generic 29
|
||||
152, // Generic 30
|
||||
156, // Generic 31
|
||||
160, // gl_FrontColor
|
||||
164, // gl_FrontSecondaryColor
|
||||
160, // gl_BackColor
|
||||
164, // gl_BackSecondaryColor
|
||||
192, // gl_TexCoord[0]
|
||||
196, // gl_TexCoord[1]
|
||||
200, // gl_TexCoord[2]
|
||||
204, // gl_TexCoord[3]
|
||||
208, // gl_TexCoord[4]
|
||||
212, // gl_TexCoord[5]
|
||||
216, // gl_TexCoord[6]
|
||||
220, // gl_TexCoord[7]
|
||||
};
|
||||
std::vector<Shader::TransformFeedbackVarying> xfb(256);
|
||||
for (size_t buffer = 0; buffer < Maxwell::NumTransformFeedbackBuffers; ++buffer) {
|
||||
const auto& locations = key.state.xfb_state.varyings[buffer];
|
||||
const auto& layout = key.state.xfb_state.layouts[buffer];
|
||||
const u32 varying_count = layout.varying_count;
|
||||
u32 highest = 0;
|
||||
for (u32 offset = 0; offset < varying_count; ++offset) {
|
||||
const u32 base_offset = offset;
|
||||
const u8 location = locations[offset];
|
||||
|
||||
Shader::TransformFeedbackVarying varying;
|
||||
varying.buffer = layout.stream;
|
||||
varying.stride = layout.stride;
|
||||
varying.offset = offset * 4;
|
||||
varying.components = 1;
|
||||
|
||||
if (std::ranges::find(VECTORS, Common::AlignDown(location, 4)) != VECTORS.end()) {
|
||||
UNIMPLEMENTED_IF_MSG(location % 4 != 0, "Unaligned TFB");
|
||||
|
||||
const u8 base_index = location / 4;
|
||||
while (offset + 1 < varying_count && base_index == locations[offset + 1] / 4) {
|
||||
++offset;
|
||||
++varying.components;
|
||||
}
|
||||
}
|
||||
xfb[location] = varying;
|
||||
highest = std::max(highest, (base_offset + varying.components) * 4);
|
||||
}
|
||||
UNIMPLEMENTED_IF(highest != layout.stride);
|
||||
}
|
||||
return xfb;
|
||||
}
|
||||
|
||||
Shader::RuntimeInfo MakeRuntimeInfo(const GraphicsPipelineCacheKey& key,
|
||||
const Shader::IR::Program& program) {
|
||||
Shader::RuntimeInfo info;
|
||||
|
||||
const Shader::Stage stage{program.stage};
|
||||
const bool has_geometry{key.unique_hashes[4] != 0};
|
||||
const bool gl_ndc{key.state.ndc_minus_one_to_one != 0};
|
||||
const float point_size{Common::BitCast<float>(key.state.point_size)};
|
||||
switch (stage) {
|
||||
case Shader::Stage::VertexB:
|
||||
if (!has_geometry) {
|
||||
if (key.state.topology == Maxwell::PrimitiveTopology::Points) {
|
||||
info.fixed_state_point_size = point_size;
|
||||
}
|
||||
if (key.state.xfb_enabled != 0) {
|
||||
info.xfb_varyings = MakeTransformFeedbackVaryings(key);
|
||||
}
|
||||
info.convert_depth_mode = gl_ndc;
|
||||
}
|
||||
std::ranges::transform(key.state.attributes, info.generic_input_types.begin(),
|
||||
&CastAttributeType);
|
||||
break;
|
||||
case Shader::Stage::TessellationEval:
|
||||
// We have to flip tessellation clockwise for some reason...
|
||||
info.tess_clockwise = key.state.tessellation_clockwise == 0;
|
||||
info.tess_primitive = [&key] {
|
||||
const u32 raw{key.state.tessellation_primitive.Value()};
|
||||
switch (static_cast<Maxwell::TessellationPrimitive>(raw)) {
|
||||
case Maxwell::TessellationPrimitive::Isolines:
|
||||
return Shader::TessPrimitive::Isolines;
|
||||
case Maxwell::TessellationPrimitive::Triangles:
|
||||
return Shader::TessPrimitive::Triangles;
|
||||
case Maxwell::TessellationPrimitive::Quads:
|
||||
return Shader::TessPrimitive::Quads;
|
||||
}
|
||||
UNREACHABLE();
|
||||
return Shader::TessPrimitive::Triangles;
|
||||
}();
|
||||
info.tess_spacing = [&] {
|
||||
const u32 raw{key.state.tessellation_spacing};
|
||||
switch (static_cast<Maxwell::TessellationSpacing>(raw)) {
|
||||
case Maxwell::TessellationSpacing::Equal:
|
||||
return Shader::TessSpacing::Equal;
|
||||
case Maxwell::TessellationSpacing::FractionalOdd:
|
||||
return Shader::TessSpacing::FractionalOdd;
|
||||
case Maxwell::TessellationSpacing::FractionalEven:
|
||||
return Shader::TessSpacing::FractionalEven;
|
||||
}
|
||||
UNREACHABLE();
|
||||
return Shader::TessSpacing::Equal;
|
||||
}();
|
||||
break;
|
||||
case Shader::Stage::Geometry:
|
||||
if (program.output_topology == Shader::OutputTopology::PointList) {
|
||||
info.fixed_state_point_size = point_size;
|
||||
}
|
||||
if (key.state.xfb_enabled != 0) {
|
||||
info.xfb_varyings = MakeTransformFeedbackVaryings(key);
|
||||
}
|
||||
info.convert_depth_mode = gl_ndc;
|
||||
break;
|
||||
case Shader::Stage::Fragment:
|
||||
info.alpha_test_func = MaxwellToCompareFunction(
|
||||
key.state.UnpackComparisonOp(key.state.alpha_test_func.Value()));
|
||||
info.alpha_test_reference = Common::BitCast<float>(key.state.alpha_test_ref);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (key.state.topology) {
|
||||
case Maxwell::PrimitiveTopology::Points:
|
||||
info.input_topology = Shader::InputTopology::Points;
|
||||
break;
|
||||
case Maxwell::PrimitiveTopology::Lines:
|
||||
case Maxwell::PrimitiveTopology::LineLoop:
|
||||
case Maxwell::PrimitiveTopology::LineStrip:
|
||||
info.input_topology = Shader::InputTopology::Lines;
|
||||
break;
|
||||
case Maxwell::PrimitiveTopology::Triangles:
|
||||
case Maxwell::PrimitiveTopology::TriangleStrip:
|
||||
case Maxwell::PrimitiveTopology::TriangleFan:
|
||||
case Maxwell::PrimitiveTopology::Quads:
|
||||
case Maxwell::PrimitiveTopology::QuadStrip:
|
||||
case Maxwell::PrimitiveTopology::Polygon:
|
||||
case Maxwell::PrimitiveTopology::Patches:
|
||||
info.input_topology = Shader::InputTopology::Triangles;
|
||||
break;
|
||||
case Maxwell::PrimitiveTopology::LinesAdjacency:
|
||||
case Maxwell::PrimitiveTopology::LineStripAdjacency:
|
||||
info.input_topology = Shader::InputTopology::LinesAdjacency;
|
||||
break;
|
||||
case Maxwell::PrimitiveTopology::TrianglesAdjacency:
|
||||
case Maxwell::PrimitiveTopology::TriangleStripAdjacency:
|
||||
info.input_topology = Shader::InputTopology::TrianglesAdjacency;
|
||||
break;
|
||||
}
|
||||
info.force_early_z = key.state.early_z != 0;
|
||||
info.y_negate = key.state.y_negate != 0;
|
||||
return info;
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
size_t ComputePipelineCacheKey::Hash() const noexcept {
|
||||
@ -124,7 +326,7 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, Tegra::Engines::Maxw
|
||||
serialization_thread(1, "yuzu:PipelineSerialization") {
|
||||
const auto& float_control{device.FloatControlProperties()};
|
||||
const VkDriverIdKHR driver_id{device.GetDriverID()};
|
||||
base_profile = Shader::Profile{
|
||||
profile = Shader::Profile{
|
||||
.supported_spirv = device.IsKhrSpirv1_4Supported() ? 0x00010400U : 0x00010000U,
|
||||
.unified_descriptor_binding = true,
|
||||
.support_descriptor_aliasing = true,
|
||||
@ -153,14 +355,10 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, Tegra::Engines::Maxw
|
||||
.support_viewport_mask = device.IsNvViewportArray2Supported(),
|
||||
.support_typeless_image_loads = device.IsFormatlessImageLoadSupported(),
|
||||
.support_demote_to_helper_invocation = true,
|
||||
.warp_size_potentially_larger_than_guest = device.IsWarpSizePotentiallyBiggerThanGuest(),
|
||||
.support_int64_atomics = device.IsExtShaderAtomicInt64Supported(),
|
||||
.warp_size_potentially_larger_than_guest = device.IsWarpSizePotentiallyBiggerThanGuest(),
|
||||
.has_broken_spirv_clamp = driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS_KHR,
|
||||
.has_broken_unsigned_image_offsets = false,
|
||||
.generic_input_types{},
|
||||
.fixed_state_point_size{},
|
||||
.alpha_test_func{},
|
||||
.xfb_varyings{},
|
||||
};
|
||||
}
|
||||
|
||||
@ -329,8 +527,8 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
|
||||
const size_t stage_index{index - 1};
|
||||
infos[stage_index] = &program.info;
|
||||
|
||||
const Shader::Profile profile{MakeProfile(key, program)};
|
||||
const std::vector<u32> code{EmitSPIRV(profile, program, binding)};
|
||||
const Shader::RuntimeInfo runtime_info{MakeRuntimeInfo(key, program)};
|
||||
const std::vector<u32> code{EmitSPIRV(profile, runtime_info, program, binding)};
|
||||
device.SaveShader(code);
|
||||
modules[stage_index] = BuildShader(device, code);
|
||||
if (device.HasDebuggingToolAttached()) {
|
||||
@ -391,7 +589,7 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline(
|
||||
|
||||
Shader::Maxwell::Flow::CFG cfg{env, pools.flow_block, env.StartAddress()};
|
||||
Shader::IR::Program program{TranslateProgram(pools.inst, pools.block, env, cfg)};
|
||||
const std::vector<u32> code{EmitSPIRV(base_profile, program)};
|
||||
const std::vector<u32> code{EmitSPIRV(profile, program)};
|
||||
device.SaveShader(code);
|
||||
vk::ShaderModule spv_module{BuildShader(device, code)};
|
||||
if (device.HasDebuggingToolAttached()) {
|
||||
@ -403,206 +601,4 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline(
|
||||
thread_worker, program.info, std::move(spv_module));
|
||||
}
|
||||
|
||||
static Shader::AttributeType CastAttributeType(const FixedPipelineState::VertexAttribute& attr) {
|
||||
if (attr.enabled == 0) {
|
||||
return Shader::AttributeType::Disabled;
|
||||
}
|
||||
switch (attr.Type()) {
|
||||
case Maxwell::VertexAttribute::Type::SignedNorm:
|
||||
case Maxwell::VertexAttribute::Type::UnsignedNorm:
|
||||
case Maxwell::VertexAttribute::Type::UnsignedScaled:
|
||||
case Maxwell::VertexAttribute::Type::SignedScaled:
|
||||
case Maxwell::VertexAttribute::Type::Float:
|
||||
return Shader::AttributeType::Float;
|
||||
case Maxwell::VertexAttribute::Type::SignedInt:
|
||||
return Shader::AttributeType::SignedInt;
|
||||
case Maxwell::VertexAttribute::Type::UnsignedInt:
|
||||
return Shader::AttributeType::UnsignedInt;
|
||||
}
|
||||
return Shader::AttributeType::Float;
|
||||
}
|
||||
|
||||
static std::vector<Shader::TransformFeedbackVarying> MakeTransformFeedbackVaryings(
|
||||
const GraphicsPipelineCacheKey& key) {
|
||||
static constexpr std::array VECTORS{
|
||||
28, // gl_Position
|
||||
32, // Generic 0
|
||||
36, // Generic 1
|
||||
40, // Generic 2
|
||||
44, // Generic 3
|
||||
48, // Generic 4
|
||||
52, // Generic 5
|
||||
56, // Generic 6
|
||||
60, // Generic 7
|
||||
64, // Generic 8
|
||||
68, // Generic 9
|
||||
72, // Generic 10
|
||||
76, // Generic 11
|
||||
80, // Generic 12
|
||||
84, // Generic 13
|
||||
88, // Generic 14
|
||||
92, // Generic 15
|
||||
96, // Generic 16
|
||||
100, // Generic 17
|
||||
104, // Generic 18
|
||||
108, // Generic 19
|
||||
112, // Generic 20
|
||||
116, // Generic 21
|
||||
120, // Generic 22
|
||||
124, // Generic 23
|
||||
128, // Generic 24
|
||||
132, // Generic 25
|
||||
136, // Generic 26
|
||||
140, // Generic 27
|
||||
144, // Generic 28
|
||||
148, // Generic 29
|
||||
152, // Generic 30
|
||||
156, // Generic 31
|
||||
160, // gl_FrontColor
|
||||
164, // gl_FrontSecondaryColor
|
||||
160, // gl_BackColor
|
||||
164, // gl_BackSecondaryColor
|
||||
192, // gl_TexCoord[0]
|
||||
196, // gl_TexCoord[1]
|
||||
200, // gl_TexCoord[2]
|
||||
204, // gl_TexCoord[3]
|
||||
208, // gl_TexCoord[4]
|
||||
212, // gl_TexCoord[5]
|
||||
216, // gl_TexCoord[6]
|
||||
220, // gl_TexCoord[7]
|
||||
};
|
||||
std::vector<Shader::TransformFeedbackVarying> xfb(256);
|
||||
for (size_t buffer = 0; buffer < Maxwell::NumTransformFeedbackBuffers; ++buffer) {
|
||||
const auto& locations = key.state.xfb_state.varyings[buffer];
|
||||
const auto& layout = key.state.xfb_state.layouts[buffer];
|
||||
const u32 varying_count = layout.varying_count;
|
||||
u32 highest = 0;
|
||||
for (u32 offset = 0; offset < varying_count; ++offset) {
|
||||
const u32 base_offset = offset;
|
||||
const u8 location = locations[offset];
|
||||
|
||||
Shader::TransformFeedbackVarying varying;
|
||||
varying.buffer = layout.stream;
|
||||
varying.stride = layout.stride;
|
||||
varying.offset = offset * 4;
|
||||
varying.components = 1;
|
||||
|
||||
if (std::ranges::find(VECTORS, Common::AlignDown(location, 4)) != VECTORS.end()) {
|
||||
UNIMPLEMENTED_IF_MSG(location % 4 != 0, "Unaligned TFB");
|
||||
|
||||
const u8 base_index = location / 4;
|
||||
while (offset + 1 < varying_count && base_index == locations[offset + 1] / 4) {
|
||||
++offset;
|
||||
++varying.components;
|
||||
}
|
||||
}
|
||||
xfb[location] = varying;
|
||||
highest = std::max(highest, (base_offset + varying.components) * 4);
|
||||
}
|
||||
UNIMPLEMENTED_IF(highest != layout.stride);
|
||||
}
|
||||
return xfb;
|
||||
}
|
||||
|
||||
Shader::Profile PipelineCache::MakeProfile(const GraphicsPipelineCacheKey& key,
|
||||
const Shader::IR::Program& program) {
|
||||
Shader::Profile profile{base_profile};
|
||||
|
||||
const Shader::Stage stage{program.stage};
|
||||
const bool has_geometry{key.unique_hashes[4] != 0};
|
||||
const bool gl_ndc{key.state.ndc_minus_one_to_one != 0};
|
||||
const float point_size{Common::BitCast<float>(key.state.point_size)};
|
||||
switch (stage) {
|
||||
case Shader::Stage::VertexB:
|
||||
if (!has_geometry) {
|
||||
if (key.state.topology == Maxwell::PrimitiveTopology::Points) {
|
||||
profile.fixed_state_point_size = point_size;
|
||||
}
|
||||
if (key.state.xfb_enabled != 0) {
|
||||
profile.xfb_varyings = MakeTransformFeedbackVaryings(key);
|
||||
}
|
||||
profile.convert_depth_mode = gl_ndc;
|
||||
}
|
||||
std::ranges::transform(key.state.attributes, profile.generic_input_types.begin(),
|
||||
&CastAttributeType);
|
||||
break;
|
||||
case Shader::Stage::TessellationEval:
|
||||
// We have to flip tessellation clockwise for some reason...
|
||||
profile.tess_clockwise = key.state.tessellation_clockwise == 0;
|
||||
profile.tess_primitive = [&key] {
|
||||
const u32 raw{key.state.tessellation_primitive.Value()};
|
||||
switch (static_cast<Maxwell::TessellationPrimitive>(raw)) {
|
||||
case Maxwell::TessellationPrimitive::Isolines:
|
||||
return Shader::TessPrimitive::Isolines;
|
||||
case Maxwell::TessellationPrimitive::Triangles:
|
||||
return Shader::TessPrimitive::Triangles;
|
||||
case Maxwell::TessellationPrimitive::Quads:
|
||||
return Shader::TessPrimitive::Quads;
|
||||
}
|
||||
UNREACHABLE();
|
||||
return Shader::TessPrimitive::Triangles;
|
||||
}();
|
||||
profile.tess_spacing = [&] {
|
||||
const u32 raw{key.state.tessellation_spacing};
|
||||
switch (static_cast<Maxwell::TessellationSpacing>(raw)) {
|
||||
case Maxwell::TessellationSpacing::Equal:
|
||||
return Shader::TessSpacing::Equal;
|
||||
case Maxwell::TessellationSpacing::FractionalOdd:
|
||||
return Shader::TessSpacing::FractionalOdd;
|
||||
case Maxwell::TessellationSpacing::FractionalEven:
|
||||
return Shader::TessSpacing::FractionalEven;
|
||||
}
|
||||
UNREACHABLE();
|
||||
return Shader::TessSpacing::Equal;
|
||||
}();
|
||||
break;
|
||||
case Shader::Stage::Geometry:
|
||||
if (program.output_topology == Shader::OutputTopology::PointList) {
|
||||
profile.fixed_state_point_size = point_size;
|
||||
}
|
||||
if (key.state.xfb_enabled != 0) {
|
||||
profile.xfb_varyings = MakeTransformFeedbackVaryings(key);
|
||||
}
|
||||
profile.convert_depth_mode = gl_ndc;
|
||||
break;
|
||||
case Shader::Stage::Fragment:
|
||||
profile.alpha_test_func = MaxwellToCompareFunction(
|
||||
key.state.UnpackComparisonOp(key.state.alpha_test_func.Value()));
|
||||
profile.alpha_test_reference = Common::BitCast<float>(key.state.alpha_test_ref);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (key.state.topology) {
|
||||
case Maxwell::PrimitiveTopology::Points:
|
||||
profile.input_topology = Shader::InputTopology::Points;
|
||||
break;
|
||||
case Maxwell::PrimitiveTopology::Lines:
|
||||
case Maxwell::PrimitiveTopology::LineLoop:
|
||||
case Maxwell::PrimitiveTopology::LineStrip:
|
||||
profile.input_topology = Shader::InputTopology::Lines;
|
||||
break;
|
||||
case Maxwell::PrimitiveTopology::Triangles:
|
||||
case Maxwell::PrimitiveTopology::TriangleStrip:
|
||||
case Maxwell::PrimitiveTopology::TriangleFan:
|
||||
case Maxwell::PrimitiveTopology::Quads:
|
||||
case Maxwell::PrimitiveTopology::QuadStrip:
|
||||
case Maxwell::PrimitiveTopology::Polygon:
|
||||
case Maxwell::PrimitiveTopology::Patches:
|
||||
profile.input_topology = Shader::InputTopology::Triangles;
|
||||
break;
|
||||
case Maxwell::PrimitiveTopology::LinesAdjacency:
|
||||
case Maxwell::PrimitiveTopology::LineStripAdjacency:
|
||||
profile.input_topology = Shader::InputTopology::LinesAdjacency;
|
||||
break;
|
||||
case Maxwell::PrimitiveTopology::TrianglesAdjacency:
|
||||
case Maxwell::PrimitiveTopology::TriangleStripAdjacency:
|
||||
profile.input_topology = Shader::InputTopology::TrianglesAdjacency;
|
||||
break;
|
||||
}
|
||||
profile.force_early_z = key.state.early_z != 0;
|
||||
profile.y_negate = key.state.y_negate != 0;
|
||||
return profile;
|
||||
}
|
||||
|
||||
} // namespace Vulkan
|
||||
|
@ -129,9 +129,6 @@ private:
|
||||
Shader::Environment& env,
|
||||
bool build_in_parallel);
|
||||
|
||||
Shader::Profile MakeProfile(const GraphicsPipelineCacheKey& key,
|
||||
const Shader::IR::Program& program);
|
||||
|
||||
const Device& device;
|
||||
VKScheduler& scheduler;
|
||||
DescriptorPool& descriptor_pool;
|
||||
@ -148,7 +145,7 @@ private:
|
||||
|
||||
ShaderPools main_pools;
|
||||
|
||||
Shader::Profile base_profile;
|
||||
Shader::Profile profile;
|
||||
std::filesystem::path pipeline_cache_filename;
|
||||
|
||||
Common::ThreadWorker workers;
|
||||
|
Loading…
Reference in New Issue
Block a user