shader: Split profile and runtime information in separate structs
This commit is contained in:
		| @@ -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 {};" | ||||
|                         "TESS_SPACING {};" | ||||
|                         "TESS_VERTEX_ORDER {};", | ||||
|                         GetTessMode(profile.tess_primitive), GetTessSpacing(profile.tess_spacing), | ||||
|                         profile.tess_clockwise ? "CW" : "CCW"); | ||||
|         header += fmt::format("TESS_MODE {};" | ||||
|                               "TESS_SPACING {};" | ||||
|                               "TESS_VERTEX_ORDER {};", | ||||
|                               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 | ||||
|                                                               : spv::ExecutionMode::VertexOrderCcw); | ||||
|         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{}; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user