summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/video_core/engines/shader_bytecode.h20
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp78
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
336enum class IsberdShift : u64 { None = 0, U16 = 1, B32 = 2 }; 336enum class IsberdShift : u64 { None = 0, U16 = 1, B32 = 2 };
337 337
338enum class HalfType : u64 {
339 H0_H1 = 0,
340 F32 = 1,
341 H0_H0 = 2,
342 H1_H1 = 3,
343};
344
345enum class HalfMerge : u64 {
346 H0_H1 = 0,
347 F32 = 1,
348 Mrg_H0 = 2,
349 Mrg_H1 = 3,
350};
351
352enum class HalfPrecision : u64 {
353 None = 0,
354 FTZ = 1,
355 FMZ = 2,
356};
357
338enum class IpaInterpMode : u64 { 358enum 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 */