forked from eden-emu/eden
		
	shader: Implement indexed attributes
This commit is contained in:
		
							parent
							
								
									0df7e509db
								
							
						
					
					
						commit
						1d51803169
					
				
					 12 changed files with 279 additions and 35 deletions
				
			
		|  | @ -82,6 +82,28 @@ Id GetAttributeType(EmitContext& ctx, AttributeType type) { | |||
|     } | ||||
|     throw InvalidArgument("Invalid attribute type {}", type); | ||||
| } | ||||
| 
 | ||||
| struct AttrInfo { | ||||
|     Id pointer; | ||||
|     Id id; | ||||
|     bool needs_cast; | ||||
| }; | ||||
| 
 | ||||
| std::optional<AttrInfo> AttrTypes(EmitContext& ctx, u32 index) { | ||||
|     const AttributeType type{ctx.profile.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); | ||||
| } | ||||
| 
 | ||||
| } // Anonymous namespace
 | ||||
| 
 | ||||
| void VectorTypes::Define(Sirit::Module& sirit_ctx, Id base_type, std::string_view name) { | ||||
|  | @ -107,6 +129,7 @@ EmitContext::EmitContext(const Profile& profile_, IR::Program& program, u32& bin | |||
|     DefineConstantBuffers(program.info, binding); | ||||
|     DefineStorageBuffers(program.info, binding); | ||||
|     DefineTextures(program.info, binding); | ||||
|     DefineAttributeMemAccess(program.info); | ||||
|     DefineLabels(program); | ||||
| } | ||||
| 
 | ||||
|  | @ -290,6 +313,107 @@ void EmitContext::DefineSharedMemory(const IR::Program& program) { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| void EmitContext::DefineAttributeMemAccess(const Info& info) { | ||||
|     const auto make_load{[&]() { | ||||
|         const Id end_block{OpLabel()}; | ||||
|         const Id default_label{OpLabel()}; | ||||
| 
 | ||||
|         const Id func_type_load{TypeFunction(F32[1], U32[1])}; | ||||
|         const Id func{OpFunction(F32[1], spv::FunctionControlMask::MaskNone, func_type_load)}; | ||||
|         const Id offset{OpFunctionParameter(U32[1])}; | ||||
|         AddLabel(); | ||||
|         const Id base_index{OpShiftRightLogical(U32[1], offset, Constant(U32[1], 2U))}; | ||||
|         const Id masked_index{OpBitwiseAnd(U32[1], base_index, Constant(U32[1], 3U))}; | ||||
|         const Id compare_index{OpShiftRightLogical(U32[1], base_index, Constant(U32[1], 2U))}; | ||||
|         std::vector<Sirit::Literal> literals; | ||||
|         std::vector<Id> labels; | ||||
|         const u32 base_attribute_value = static_cast<u32>(IR::Attribute::Generic0X) >> 2; | ||||
|         for (u32 i = 0; i < info.input_generics.size(); i++) { | ||||
|             if (!info.input_generics[i].used) { | ||||
|                 continue; | ||||
|             } | ||||
|             literals.push_back(base_attribute_value + i); | ||||
|             labels.push_back(OpLabel()); | ||||
|         } | ||||
|         OpSelectionMerge(end_block, spv::SelectionControlMask::MaskNone); | ||||
|         OpSwitch(compare_index, default_label, literals, labels); | ||||
|         AddLabel(default_label); | ||||
|         OpReturnValue(Constant(F32[1], 0.0f)); | ||||
|         size_t label_index = 0; | ||||
|         for (u32 i = 0; i < info.input_generics.size(); i++) { | ||||
|             if (!info.input_generics[i].used) { | ||||
|                 continue; | ||||
|             } | ||||
|             AddLabel(labels[label_index]); | ||||
|             const auto type{AttrTypes(*this, i)}; | ||||
|             if (!type) { | ||||
|                 OpReturnValue(Constant(F32[1], 0.0f)); | ||||
|                 label_index++; | ||||
|                 continue; | ||||
|             } | ||||
|             const Id generic_id{input_generics.at(i)}; | ||||
|             const Id pointer{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++; | ||||
|         } | ||||
|         AddLabel(end_block); | ||||
|         OpUnreachable(); | ||||
|         OpFunctionEnd(); | ||||
|         return func; | ||||
|     }}; | ||||
|     const auto make_store{[&]() { | ||||
|         const Id end_block{OpLabel()}; | ||||
|         const Id default_label{OpLabel()}; | ||||
| 
 | ||||
|         const Id func_type_store{TypeFunction(void_id, U32[1], F32[1])}; | ||||
|         const Id func{OpFunction(void_id, spv::FunctionControlMask::MaskNone, func_type_store)}; | ||||
|         const Id offset{OpFunctionParameter(U32[1])}; | ||||
|         const Id store_value{OpFunctionParameter(F32[1])}; | ||||
|         AddLabel(); | ||||
|         const Id base_index{OpShiftRightLogical(U32[1], offset, Constant(U32[1], 2U))}; | ||||
|         const Id masked_index{OpBitwiseAnd(U32[1], base_index, Constant(U32[1], 3U))}; | ||||
|         const Id compare_index{OpShiftRightLogical(U32[1], base_index, Constant(U32[1], 2U))}; | ||||
|         std::vector<Sirit::Literal> literals; | ||||
|         std::vector<Id> labels; | ||||
|         const u32 base_attribute_value = static_cast<u32>(IR::Attribute::Generic0X) >> 2; | ||||
|         for (u32 i = 0; i < info.stores_generics.size(); i++) { | ||||
|             if (!info.stores_generics[i]) { | ||||
|                 continue; | ||||
|             } | ||||
|             literals.push_back(base_attribute_value + i); | ||||
|             labels.push_back(OpLabel()); | ||||
|         } | ||||
|         OpSelectionMerge(end_block, spv::SelectionControlMask::MaskNone); | ||||
|         OpSwitch(compare_index, default_label, literals, labels); | ||||
|         AddLabel(default_label); | ||||
|         OpReturn(); | ||||
|         size_t label_index = 0; | ||||
|         for (u32 i = 0; i < info.stores_generics.size(); i++) { | ||||
|             if (!info.stores_generics[i]) { | ||||
|                 continue; | ||||
|             } | ||||
|             AddLabel(labels[label_index]); | ||||
|             const Id generic_id{output_generics.at(i)}; | ||||
|             const Id pointer{OpAccessChain(output_f32, generic_id, masked_index)}; | ||||
|             OpStore(pointer, store_value); | ||||
|             OpReturn(); | ||||
|             label_index++; | ||||
|         } | ||||
|         AddLabel(end_block); | ||||
|         OpUnreachable(); | ||||
|         OpFunctionEnd(); | ||||
|         return func; | ||||
|     }}; | ||||
|     if (info.loads_indexed_attributes) { | ||||
|         indexed_load_func = make_load(); | ||||
|     } | ||||
|     if (info.stores_indexed_attributes) { | ||||
|         indexed_store_func = make_store(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void EmitContext::DefineConstantBuffers(const Info& info, u32& binding) { | ||||
|     if (info.constant_buffer_descriptors.empty()) { | ||||
|         return; | ||||
|  |  | |||
|  | @ -116,6 +116,9 @@ public: | |||
|     Id fswzadd_lut_a{}; | ||||
|     Id fswzadd_lut_b{}; | ||||
| 
 | ||||
|     Id indexed_load_func{}; | ||||
|     Id indexed_store_func{}; | ||||
| 
 | ||||
|     Id local_memory{}; | ||||
| 
 | ||||
|     Id shared_memory_u8{}; | ||||
|  | @ -148,6 +151,7 @@ private: | |||
|     void DefineConstantBuffers(const Info& info, u32& binding); | ||||
|     void DefineStorageBuffers(const Info& info, u32& binding); | ||||
|     void DefineTextures(const Info& info, u32& binding); | ||||
|     void DefineAttributeMemAccess(const Info& info); | ||||
|     void DefineLabels(IR::Program& program); | ||||
| 
 | ||||
|     void DefineConstantBuffers(const Info& info, Id UniformDefinitions::*member_type, u32 binding, | ||||
|  |  | |||
|  | @ -51,8 +51,8 @@ Id EmitGetCbufF32(EmitContext& ctx, const IR::Value& binding, const IR::Value& o | |||
| Id EmitGetCbufU32x2(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset); | ||||
| Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr); | ||||
| void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, Id value); | ||||
| void EmitGetAttributeIndexed(EmitContext& ctx); | ||||
| void EmitSetAttributeIndexed(EmitContext& ctx); | ||||
| Id EmitGetAttributeIndexed(EmitContext& ctx, Id offset); | ||||
| void EmitSetAttributeIndexed(EmitContext& ctx, Id offset, Id value); | ||||
| void EmitSetFragColor(EmitContext& ctx, u32 index, u32 component, Id value); | ||||
| void EmitSetFragDepth(EmitContext& ctx, Id value); | ||||
| void EmitGetZFlag(EmitContext& ctx); | ||||
|  |  | |||
|  | @ -216,12 +216,12 @@ void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, Id value) { | |||
|     ctx.OpStore(*output, value); | ||||
| } | ||||
| 
 | ||||
| void EmitGetAttributeIndexed(EmitContext&) { | ||||
|     throw NotImplementedException("SPIR-V Instruction"); | ||||
| Id EmitGetAttributeIndexed(EmitContext& ctx, Id offset) { | ||||
|     return ctx.OpFunctionCall(ctx.F32[1], ctx.indexed_load_func, offset); | ||||
| } | ||||
| 
 | ||||
| void EmitSetAttributeIndexed(EmitContext&) { | ||||
|     throw NotImplementedException("SPIR-V Instruction"); | ||||
| void EmitSetAttributeIndexed(EmitContext& ctx, Id offset, Id value) { | ||||
|     ctx.OpFunctionCall(ctx.void_id, ctx.indexed_store_func, offset, value); | ||||
| } | ||||
| 
 | ||||
| void EmitSetFragColor(EmitContext& ctx, u32 index, u32 component, Id value) { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 FernandoS27
						FernandoS27