forked from eden-emu/eden
		
	shader_decompiler: Improve Accuracy of Attribute Interpolation.
This commit is contained in:
		
							parent
							
								
									8490e7746a
								
							
						
					
					
						commit
						10682ad7e0
					
				
					 6 changed files with 74 additions and 38 deletions
				
			
		|  | @ -376,9 +376,9 @@ enum class R2pMode : u64 { | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| enum class IpaInterpMode : u64 { | enum class IpaInterpMode : u64 { | ||||||
|     Linear = 0, |     Pass = 0, | ||||||
|     Perspective = 1, |     Multiply = 1, | ||||||
|     Flat = 2, |     Constant = 2, | ||||||
|     Sc = 3, |     Sc = 3, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -16,6 +16,13 @@ enum class OutputTopology : u32 { | ||||||
|     TriangleStrip = 7, |     TriangleStrip = 7, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | enum class AttributeUse : u8 { | ||||||
|  |     Unused = 0, | ||||||
|  |     Constant = 1, | ||||||
|  |     Perspective = 2, | ||||||
|  |     ScreenLinear = 3, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| // Documentation in:
 | // Documentation in:
 | ||||||
| // http://download.nvidia.com/open-gpu-doc/Shader-Program-Header/1/Shader-Program-Header.html#ImapTexture
 | // http://download.nvidia.com/open-gpu-doc/Shader-Program-Header/1/Shader-Program-Header.html#ImapTexture
 | ||||||
| struct Header { | struct Header { | ||||||
|  | @ -86,7 +93,13 @@ struct Header { | ||||||
|         struct { |         struct { | ||||||
|             INSERT_PADDING_BYTES(3); // ImapSystemValuesA
 |             INSERT_PADDING_BYTES(3); // ImapSystemValuesA
 | ||||||
|             INSERT_PADDING_BYTES(1); // ImapSystemValuesB
 |             INSERT_PADDING_BYTES(1); // ImapSystemValuesB
 | ||||||
|             INSERT_PADDING_BYTES(32); // ImapGenericVector[32]
 |             union { | ||||||
|  |                 BitField<0, 2, AttributeUse> x; | ||||||
|  |                 BitField<2, 2, AttributeUse> y; | ||||||
|  |                 BitField<4, 2, AttributeUse> w; | ||||||
|  |                 BitField<6, 2, AttributeUse> z; | ||||||
|  |                 u8 raw; | ||||||
|  |             } imap_generic_vector[32]; | ||||||
|             INSERT_PADDING_BYTES(2);  // ImapColor
 |             INSERT_PADDING_BYTES(2);  // ImapColor
 | ||||||
|             INSERT_PADDING_BYTES(2);  // ImapSystemValuesC
 |             INSERT_PADDING_BYTES(2);  // ImapSystemValuesC
 | ||||||
|             INSERT_PADDING_BYTES(10); // ImapFixedFncTexture[10]
 |             INSERT_PADDING_BYTES(10); // ImapFixedFncTexture[10]
 | ||||||
|  | @ -103,6 +116,28 @@ struct Header { | ||||||
|                 const u32 bit = render_target * 4 + component; |                 const u32 bit = render_target * 4 + component; | ||||||
|                 return omap.target & (1 << bit); |                 return omap.target & (1 << bit); | ||||||
|             } |             } | ||||||
|  |             AttributeUse GetAttributeIndexUse(u32 attribute, u32 index) const { | ||||||
|  |                 return static_cast<AttributeUse>( | ||||||
|  |                     (imap_generic_vector[attribute].raw >> (index * 2)) & 0x03); | ||||||
|  |             } | ||||||
|  |             AttributeUse GetAttributeUse(u32 attribute) const { | ||||||
|  |                 AttributeUse result = AttributeUse::Unused; | ||||||
|  |                 for (u32 i = 0; i < 4; i++) { | ||||||
|  |                     const auto index = GetAttributeIndexUse(attribute, i); | ||||||
|  |                     if (index == AttributeUse::Unused) { | ||||||
|  |                         continue; | ||||||
|  |                     } | ||||||
|  |                     if (result == AttributeUse::Unused || result == index) { | ||||||
|  |                         result = index; | ||||||
|  |                         continue; | ||||||
|  |                     } | ||||||
|  |                     LOG_CRITICAL(HW_GPU, "Generic Attribute Conflict in Interpolation Mode"); | ||||||
|  |                     if (index == AttributeUse::Perspective) { | ||||||
|  |                         result = index; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 return result; | ||||||
|  |             } | ||||||
|         } ps; |         } ps; | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -20,6 +20,7 @@ | ||||||
| namespace OpenGL::GLShader { | namespace OpenGL::GLShader { | ||||||
| 
 | 
 | ||||||
| using Tegra::Shader::Attribute; | using Tegra::Shader::Attribute; | ||||||
|  | using Tegra::Shader::AttributeUse; | ||||||
| using Tegra::Shader::Header; | using Tegra::Shader::Header; | ||||||
| using Tegra::Shader::IpaInterpMode; | using Tegra::Shader::IpaInterpMode; | ||||||
| using Tegra::Shader::IpaMode; | using Tegra::Shader::IpaMode; | ||||||
|  | @ -288,34 +289,22 @@ private: | ||||||
|         code.AddNewLine(); |         code.AddNewLine(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     std::string GetInputFlags(const IpaMode& input_mode) { |     std::string GetInputFlags(AttributeUse attribute) { | ||||||
|         const IpaSampleMode sample_mode = input_mode.sampling_mode; |  | ||||||
|         const IpaInterpMode interp_mode = input_mode.interpolation_mode; |  | ||||||
|         std::string out; |         std::string out; | ||||||
| 
 | 
 | ||||||
|         switch (interp_mode) { |         switch (attribute) { | ||||||
|         case IpaInterpMode::Flat: |         case AttributeUse::Constant: | ||||||
|             out += "flat "; |             out += "flat "; | ||||||
|             break; |             break; | ||||||
|         case IpaInterpMode::Linear: |         case AttributeUse::ScreenLinear: | ||||||
|             out += "noperspective "; |             out += "noperspective "; | ||||||
|             break; |             break; | ||||||
|         case IpaInterpMode::Perspective: |         case AttributeUse::Perspective: | ||||||
|             // Default, Smooth
 |             // Default, Smooth
 | ||||||
|             break; |             break; | ||||||
|         default: |         default: | ||||||
|             UNIMPLEMENTED_MSG("Unhandled IPA interp mode: {}", static_cast<u32>(interp_mode)); |             LOG_CRITICAL(HW_GPU, "Unused attribute being fetched"); | ||||||
|         } |             UNREACHABLE(); | ||||||
|         switch (sample_mode) { |  | ||||||
|         case IpaSampleMode::Centroid: |  | ||||||
|             // It can be implemented with the "centroid " keyword in GLSL
 |  | ||||||
|             UNIMPLEMENTED_MSG("Unimplemented IPA sampler mode centroid"); |  | ||||||
|             break; |  | ||||||
|         case IpaSampleMode::Default: |  | ||||||
|             // Default, n/a
 |  | ||||||
|             break; |  | ||||||
|         default: |  | ||||||
|             UNIMPLEMENTED_MSG("Unimplemented IPA sampler mode: {}", static_cast<u32>(sample_mode)); |  | ||||||
|         } |         } | ||||||
|         return out; |         return out; | ||||||
|     } |     } | ||||||
|  | @ -324,16 +313,11 @@ private: | ||||||
|         const auto& attributes = ir.GetInputAttributes(); |         const auto& attributes = ir.GetInputAttributes(); | ||||||
|         for (const auto element : attributes) { |         for (const auto element : attributes) { | ||||||
|             const Attribute::Index index = element.first; |             const Attribute::Index index = element.first; | ||||||
|             const IpaMode& input_mode = *element.second.begin(); |  | ||||||
|             if (index < Attribute::Index::Attribute_0 || index > Attribute::Index::Attribute_31) { |             if (index < Attribute::Index::Attribute_0 || index > Attribute::Index::Attribute_31) { | ||||||
|                 // Skip when it's not a generic attribute
 |                 // Skip when it's not a generic attribute
 | ||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             ASSERT(element.second.size() > 0); |  | ||||||
|             UNIMPLEMENTED_IF_MSG(element.second.size() > 1, |  | ||||||
|                                  "Multiple input flag modes are not supported in GLSL"); |  | ||||||
| 
 |  | ||||||
|             // TODO(bunnei): Use proper number of elements for these
 |             // TODO(bunnei): Use proper number of elements for these
 | ||||||
|             u32 idx = static_cast<u32>(index) - static_cast<u32>(Attribute::Index::Attribute_0); |             u32 idx = static_cast<u32>(index) - static_cast<u32>(Attribute::Index::Attribute_0); | ||||||
|             if (stage != ShaderStage::Vertex) { |             if (stage != ShaderStage::Vertex) { | ||||||
|  | @ -345,8 +329,14 @@ private: | ||||||
|             if (stage == ShaderStage::Geometry) { |             if (stage == ShaderStage::Geometry) { | ||||||
|                 attr = "gs_" + attr + "[]"; |                 attr = "gs_" + attr + "[]"; | ||||||
|             } |             } | ||||||
|             code.AddLine("layout (location = " + std::to_string(idx) + ") " + |             std::string suffix; | ||||||
|                          GetInputFlags(input_mode) + "in vec4 " + attr + ';'); |             if (stage == ShaderStage::Fragment) { | ||||||
|  |                 const auto input_mode = | ||||||
|  |                     header.ps.GetAttributeUse(idx - GENERIC_VARYING_START_LOCATION); | ||||||
|  |                 suffix = GetInputFlags(input_mode); | ||||||
|  |             } | ||||||
|  |             code.AddLine("layout (location = " + std::to_string(idx) + ") " + suffix + "in vec4 " + | ||||||
|  |                          attr + ';'); | ||||||
|         } |         } | ||||||
|         if (!attributes.empty()) |         if (!attributes.empty()) | ||||||
|             code.AddNewLine(); |             code.AddNewLine(); | ||||||
|  |  | ||||||
|  | @ -124,7 +124,7 @@ layout (location = 5) out vec4 FragColor5; | ||||||
| layout (location = 6) out vec4 FragColor6; | layout (location = 6) out vec4 FragColor6; | ||||||
| layout (location = 7) out vec4 FragColor7; | layout (location = 7) out vec4 FragColor7; | ||||||
| 
 | 
 | ||||||
| layout (location = 0) in vec4 position; | layout (location = 0) in noperspective vec4 position; | ||||||
| 
 | 
 | ||||||
| layout (std140, binding = EMULATION_UBO_BINDING) uniform fs_config { | layout (std140, binding = EMULATION_UBO_BINDING) uniform fs_config { | ||||||
|     vec4 viewport_flip; |     vec4 viewport_flip; | ||||||
|  |  | ||||||
|  | @ -48,7 +48,7 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) { | ||||||
|         UNIMPLEMENTED_IF_MSG((instr.attribute.fmt20.immediate.Value() % sizeof(u32)) != 0, |         UNIMPLEMENTED_IF_MSG((instr.attribute.fmt20.immediate.Value() % sizeof(u32)) != 0, | ||||||
|                              "Unaligned attribute loads are not supported"); |                              "Unaligned attribute loads are not supported"); | ||||||
| 
 | 
 | ||||||
|         Tegra::Shader::IpaMode input_mode{Tegra::Shader::IpaInterpMode::Perspective, |         Tegra::Shader::IpaMode input_mode{Tegra::Shader::IpaInterpMode::Pass, | ||||||
|                                           Tegra::Shader::IpaSampleMode::Default}; |                                           Tegra::Shader::IpaSampleMode::Default}; | ||||||
| 
 | 
 | ||||||
|         u64 next_element = instr.attribute.fmt20.element; |         u64 next_element = instr.attribute.fmt20.element; | ||||||
|  |  | ||||||
|  | @ -135,7 +135,18 @@ u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) { | ||||||
|                                                 instr.ipa.sample_mode.Value()}; |                                                 instr.ipa.sample_mode.Value()}; | ||||||
| 
 | 
 | ||||||
|         const Node attr = GetInputAttribute(attribute.index, attribute.element, input_mode); |         const Node attr = GetInputAttribute(attribute.index, attribute.element, input_mode); | ||||||
|         const Node value = GetSaturatedFloat(attr, instr.ipa.saturate); |         Node value = attr; | ||||||
|  |         const Tegra::Shader::Attribute::Index index = attribute.index.Value(); | ||||||
|  |         if (index >= Tegra::Shader::Attribute::Index::Attribute_0 && | ||||||
|  |             index <= Tegra::Shader::Attribute::Index::Attribute_31) { | ||||||
|  |             // TODO(Blinkhawk): There are cases where a perspective attribute use PASS.
 | ||||||
|  |             // In theory by setting them as perspective, OpenGL does the perspective correction.
 | ||||||
|  |             // A way must figured to reverse the last step of it.
 | ||||||
|  |             if (input_mode.interpolation_mode == Tegra::Shader::IpaInterpMode::Multiply) { | ||||||
|  |                 value = Operation(OperationCode::FMul, PRECISE, value, GetRegister(instr.gpr20)); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         value = GetSaturatedFloat(value, instr.ipa.saturate); | ||||||
| 
 | 
 | ||||||
|         SetRegister(bb, instr.gpr0, value); |         SetRegister(bb, instr.gpr0, value); | ||||||
|         break; |         break; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Fernando Sahmkow
						Fernando Sahmkow