gl_shader_decompiler: Use an if based cbuf indexing for broken drivers
The following code is broken on AMD's proprietary GLSL compiler: ```glsl uint idx = ...; vec4 values = ...; float some_value = values[idx & 3]; ``` It index the wrong components, to fix this the following pessimized code is emitted when that bug is present: ```glsl uint idx = ...; vec4 values = ...; float some_value; if ((idx & 3) == 0) some_value = values.x; if ((idx & 3) == 1) some_value = values.y; if ((idx & 3) == 2) some_value = values.z; if ((idx & 3) == 3) some_value = values.w; ```
This commit is contained in:
		| @@ -577,9 +577,26 @@ private: | |||||||
|             if (std::holds_alternative<OperationNode>(*offset)) { |             if (std::holds_alternative<OperationNode>(*offset)) { | ||||||
|                 // Indirect access |                 // Indirect access | ||||||
|                 const std::string final_offset = code.GenerateTemporary(); |                 const std::string final_offset = code.GenerateTemporary(); | ||||||
|                 code.AddLine("uint {} = (ftou({}) / 4);", final_offset, Visit(offset)); |                 code.AddLine("uint {} = ftou({}) >> 2;", final_offset, Visit(offset)); | ||||||
|                 return fmt::format("{}[{} / 4][{} % 4]", GetConstBuffer(cbuf->GetIndex()), |  | ||||||
|                                    final_offset, final_offset); |                 if (!device.HasComponentIndexingBug()) { | ||||||
|  |                     return fmt::format("{}[{} >> 2][{} & 3]", GetConstBuffer(cbuf->GetIndex()), | ||||||
|  |                                        final_offset, final_offset); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 // AMD's proprietary GLSL compiler emits ill code for variable component access. | ||||||
|  |                 // To bypass this driver bug generate 4 ifs, one per each component. | ||||||
|  |                 const std::string pack = code.GenerateTemporary(); | ||||||
|  |                 code.AddLine("vec4 {} = {}[{} >> 2];", pack, GetConstBuffer(cbuf->GetIndex()), | ||||||
|  |                              final_offset); | ||||||
|  |  | ||||||
|  |                 const std::string result = code.GenerateTemporary(); | ||||||
|  |                 code.AddLine("float {};", result); | ||||||
|  |                 for (u32 swizzle = 0; swizzle < 4; ++swizzle) { | ||||||
|  |                     code.AddLine("if (({} & 3) == {}) {} = {}{};", final_offset, swizzle, result, | ||||||
|  |                                  pack, GetSwizzle(swizzle)); | ||||||
|  |                 } | ||||||
|  |                 return result; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             UNREACHABLE_MSG("Unmanaged offset node type"); |             UNREACHABLE_MSG("Unmanaged offset node type"); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user