diff options
| -rw-r--r-- | src/video_core/engines/shader_bytecode.h | 20 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 78 |
2 files changed, 98 insertions, 0 deletions
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index 9a59b65b3..d6d46d277 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h | |||
| @@ -335,6 +335,26 @@ enum class IsberdMode : u64 { | |||
| 335 | 335 | ||
| 336 | enum class IsberdShift : u64 { None = 0, U16 = 1, B32 = 2 }; | 336 | enum class IsberdShift : u64 { None = 0, U16 = 1, B32 = 2 }; |
| 337 | 337 | ||
| 338 | enum class HalfType : u64 { | ||
| 339 | H0_H1 = 0, | ||
| 340 | F32 = 1, | ||
| 341 | H0_H0 = 2, | ||
| 342 | H1_H1 = 3, | ||
| 343 | }; | ||
| 344 | |||
| 345 | enum class HalfMerge : u64 { | ||
| 346 | H0_H1 = 0, | ||
| 347 | F32 = 1, | ||
| 348 | Mrg_H0 = 2, | ||
| 349 | Mrg_H1 = 3, | ||
| 350 | }; | ||
| 351 | |||
| 352 | enum class HalfPrecision : u64 { | ||
| 353 | None = 0, | ||
| 354 | FTZ = 1, | ||
| 355 | FMZ = 2, | ||
| 356 | }; | ||
| 357 | |||
| 338 | enum class IpaInterpMode : u64 { | 358 | enum class IpaInterpMode : u64 { |
| 339 | Linear = 0, | 359 | Linear = 0, |
| 340 | Perspective = 1, | 360 | Perspective = 1, |
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 8dfb49507..c6ae8c3b4 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -376,6 +376,49 @@ public: | |||
| 376 | } | 376 | } |
| 377 | 377 | ||
| 378 | /** | 378 | /** |
| 379 | * Writes code that does a register assignment to a half float value operation. | ||
| 380 | * @param reg The destination register to use. | ||
| 381 | * @param elem The element to use for the operation. | ||
| 382 | * @param value The code representing the value to assign. Type has to be half float. | ||
| 383 | * @param type Half float kind of assignment. | ||
| 384 | * @param dest_num_components Number of components in the destionation. | ||
| 385 | * @param value_num_components Number of components in the value. | ||
| 386 | * @param is_saturated Optional, when True, saturates the provided value. | ||
| 387 | * @param dest_elem Optional, the destination element to use for the operation. | ||
| 388 | */ | ||
| 389 | void SetRegisterToHalfFloat(const Register& reg, u64 elem, const std::string& value, | ||
| 390 | Tegra::Shader::HalfMerge merge, u64 dest_num_components, | ||
| 391 | u64 value_num_components, bool is_saturated = false, | ||
| 392 | u64 dest_elem = 0) { | ||
| 393 | ASSERT_MSG(!is_saturated, "Unimplemented"); | ||
| 394 | |||
| 395 | const std::string result = [&]() { | ||
| 396 | switch (merge) { | ||
| 397 | case Tegra::Shader::HalfMerge::H0_H1: | ||
| 398 | return "uintBitsToFloat(packHalf2x16(" + value + "))"; | ||
| 399 | case Tegra::Shader::HalfMerge::F32: | ||
| 400 | // Half float instructions take the first component when doing a float cast. | ||
| 401 | return "float(" + value + ".x)"; | ||
| 402 | case Tegra::Shader::HalfMerge::Mrg_H0: | ||
| 403 | // TODO(Rodrigo): I guess Mrg_H0 and Mrg_H1 take their respective component from the | ||
| 404 | // pack. I couldn't test this on hardware but it shouldn't really matter since most | ||
| 405 | // of the time when a Mrg_* flag is used both components will be mirrored. That | ||
| 406 | // being said, it deserves a test. | ||
| 407 | return "((" + GetRegisterAsInteger(reg, 0, false) + | ||
| 408 | " & 0xffff0000) | (packHalf2x16(" + value + ") & 0x0000ffff))"; | ||
| 409 | case Tegra::Shader::HalfMerge::Mrg_H1: | ||
| 410 | return "((" + GetRegisterAsInteger(reg, 0, false) + | ||
| 411 | " & 0x0000ffff) | (packHalf2x16(" + value + ") & 0xffff0000))"; | ||
| 412 | default: | ||
| 413 | UNREACHABLE(); | ||
| 414 | return std::string("0"); | ||
| 415 | } | ||
| 416 | }(); | ||
| 417 | |||
| 418 | SetRegister(reg, elem, result, dest_num_components, value_num_components, dest_elem); | ||
| 419 | } | ||
| 420 | |||
| 421 | /** | ||
| 379 | * Writes code that does a register assignment to input attribute operation. Input attributes | 422 | * Writes code that does a register assignment to input attribute operation. Input attributes |
| 380 | * are stored as floats, so this may require conversion. | 423 | * are stored as floats, so this may require conversion. |
| 381 | * @param reg The destination register to use. | 424 | * @param reg The destination register to use. |
| @@ -1013,6 +1056,41 @@ private: | |||
| 1013 | } | 1056 | } |
| 1014 | 1057 | ||
| 1015 | /* | 1058 | /* |
| 1059 | * Transforms the input string GLSL operand into an unpacked half float pair. | ||
| 1060 | * @note This function returns a float type pair instead of a half float pair. This is because | ||
| 1061 | * real half floats are not standarized in GLSL but unpackHalf2x16 (which returns a vec2) is. | ||
| 1062 | * @param operand Input operand. It has to be an unsigned integer. | ||
| 1063 | * @param type How to unpack the unsigned integer to a half float pair. | ||
| 1064 | * @param abs Get the absolute value of unpacked half floats. | ||
| 1065 | * @param neg Get the negative value of unpacked half floats. | ||
| 1066 | * @returns String corresponding to a half float pair. | ||
| 1067 | */ | ||
| 1068 | static std::string GetHalfFloat(const std::string& operand, | ||
| 1069 | Tegra::Shader::HalfType type = Tegra::Shader::HalfType::H0_H1, | ||
| 1070 | bool abs = false, bool neg = false) { | ||
| 1071 | // "vec2" calls emitted in this function are intended to alias components. | ||
| 1072 | const std::string value = [&]() { | ||
| 1073 | switch (type) { | ||
| 1074 | case Tegra::Shader::HalfType::H0_H1: | ||
| 1075 | return "unpackHalf2x16(" + operand + ')'; | ||
| 1076 | case Tegra::Shader::HalfType::F32: | ||
| 1077 | return "vec2(uintBitsToFloat(" + operand + "))"; | ||
| 1078 | case Tegra::Shader::HalfType::H0_H0: | ||
| 1079 | case Tegra::Shader::HalfType::H1_H1: { | ||
| 1080 | const bool high = type == Tegra::Shader::HalfType::H1_H1; | ||
| 1081 | const char unpack_index = "xy"[high ? 1 : 0]; | ||
| 1082 | return "vec2(unpackHalf2x16(" + operand + ")." + unpack_index + ')'; | ||
| 1083 | } | ||
| 1084 | default: | ||
| 1085 | UNREACHABLE(); | ||
| 1086 | return std::string("vec2(0)"); | ||
| 1087 | } | ||
| 1088 | }(); | ||
| 1089 | |||
| 1090 | return GetOperandAbsNeg(value, abs, neg); | ||
| 1091 | } | ||
| 1092 | |||
| 1093 | /* | ||
| 1016 | * Returns whether the instruction at the specified offset is a 'sched' instruction. | 1094 | * Returns whether the instruction at the specified offset is a 'sched' instruction. |
| 1017 | * Sched instructions always appear before a sequence of 3 instructions. | 1095 | * Sched instructions always appear before a sequence of 3 instructions. |
| 1018 | */ | 1096 | */ |