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,11 +577,28 @@ private: | ||||
|             if (std::holds_alternative<OperationNode>(*offset)) { | ||||
|                 // Indirect access | ||||
|                 const std::string final_offset = code.GenerateTemporary(); | ||||
|                 code.AddLine("uint {} = (ftou({}) / 4);", final_offset, Visit(offset)); | ||||
|                 return fmt::format("{}[{} / 4][{} % 4]", GetConstBuffer(cbuf->GetIndex()), | ||||
|                 code.AddLine("uint {} = ftou({}) >> 2;", final_offset, Visit(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"); | ||||
|         } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user