summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/service/nfp/nfp.cpp108
-rw-r--r--src/video_core/engines/shader_bytecode.h35
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp8
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp59
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp13
-rw-r--r--src/video_core/renderer_opengl/gl_state.h6
-rw-r--r--src/video_core/renderer_opengl/maxwell_to_gl.h21
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp1
-rw-r--r--src/video_core/textures/texture.h16
9 files changed, 234 insertions, 33 deletions
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp
index 2af4465de..2a9f84037 100644
--- a/src/core/hle/service/nfp/nfp.cpp
+++ b/src/core/hle/service/nfp/nfp.cpp
@@ -4,6 +4,8 @@
4 4
5#include "common/logging/log.h" 5#include "common/logging/log.h"
6#include "core/hle/ipc_helpers.h" 6#include "core/hle/ipc_helpers.h"
7#include "core/hle/kernel/event.h"
8#include "core/hle/service/hid/hid.h"
7#include "core/hle/service/nfp/nfp.h" 9#include "core/hle/service/nfp/nfp.h"
8#include "core/hle/service/nfp/nfp_user.h" 10#include "core/hle/service/nfp/nfp_user.h"
9 11
@@ -18,7 +20,7 @@ public:
18 static const FunctionInfo functions[] = { 20 static const FunctionInfo functions[] = {
19 {0, &IUser::Initialize, "Initialize"}, 21 {0, &IUser::Initialize, "Initialize"},
20 {1, nullptr, "Finalize"}, 22 {1, nullptr, "Finalize"},
21 {2, nullptr, "ListDevices"}, 23 {2, &IUser::ListDevices, "ListDevices"},
22 {3, nullptr, "StartDetection"}, 24 {3, nullptr, "StartDetection"},
23 {4, nullptr, "StopDetection"}, 25 {4, nullptr, "StopDetection"},
24 {5, nullptr, "Mount"}, 26 {5, nullptr, "Mount"},
@@ -33,24 +35,116 @@ public:
33 {14, nullptr, "GetRegisterInfo"}, 35 {14, nullptr, "GetRegisterInfo"},
34 {15, nullptr, "GetCommonInfo"}, 36 {15, nullptr, "GetCommonInfo"},
35 {16, nullptr, "GetModelInfo"}, 37 {16, nullptr, "GetModelInfo"},
36 {17, nullptr, "AttachActivateEvent"}, 38 {17, &IUser::AttachActivateEvent, "AttachActivateEvent"},
37 {18, nullptr, "AttachDeactivateEvent"}, 39 {18, &IUser::AttachDeactivateEvent, "AttachDeactivateEvent"},
38 {19, nullptr, "GetState"}, 40 {19, &IUser::GetState, "GetState"},
39 {20, nullptr, "GetDeviceState"}, 41 {20, &IUser::GetDeviceState, "GetDeviceState"},
40 {21, nullptr, "GetNpadId"}, 42 {21, &IUser::GetNpadId, "GetNpadId"},
41 {22, nullptr, "GetApplicationArea2"}, 43 {22, nullptr, "GetApplicationArea2"},
42 {23, nullptr, "AttachAvailabilityChangeEvent"}, 44 {23, &IUser::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
43 {24, nullptr, "RecreateApplicationArea"}, 45 {24, nullptr, "RecreateApplicationArea"},
44 }; 46 };
45 RegisterHandlers(functions); 47 RegisterHandlers(functions);
48
49 activate_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "IUser:ActivateEvent");
50 deactivate_event =
51 Kernel::Event::Create(Kernel::ResetType::OneShot, "IUser:DeactivateEvent");
52 availability_change_event =
53 Kernel::Event::Create(Kernel::ResetType::OneShot, "IUser:AvailabilityChangeEvent");
46 } 54 }
47 55
48private: 56private:
57 enum class State : u32 {
58 NonInitialized = 0,
59 Initialized = 1,
60 };
61
62 enum class DeviceState : u32 {
63 Initialized = 0,
64 };
65
49 void Initialize(Kernel::HLERequestContext& ctx) { 66 void Initialize(Kernel::HLERequestContext& ctx) {
50 NGLOG_WARNING(Service_NFP, "(STUBBED) called"); 67 NGLOG_WARNING(Service_NFP, "(STUBBED) called");
68
69 state = State::Initialized;
70
51 IPC::ResponseBuilder rb{ctx, 2}; 71 IPC::ResponseBuilder rb{ctx, 2};
52 rb.Push(RESULT_SUCCESS); 72 rb.Push(RESULT_SUCCESS);
53 } 73 }
74
75 void ListDevices(Kernel::HLERequestContext& ctx) {
76 IPC::RequestParser rp{ctx};
77 const u32 array_size = rp.Pop<u32>();
78
79 ctx.WriteBuffer(&device_handle, sizeof(device_handle));
80
81 NGLOG_WARNING(Service_NFP, "(STUBBED) called, array_size={}", array_size);
82
83 IPC::ResponseBuilder rb{ctx, 3};
84 rb.Push(RESULT_SUCCESS);
85 rb.Push<u32>(0);
86 }
87
88 void AttachActivateEvent(Kernel::HLERequestContext& ctx) {
89 IPC::RequestParser rp{ctx};
90 const u64 dev_handle = rp.Pop<u64>();
91 NGLOG_WARNING(Service_NFP, "(STUBBED) called, dev_handle=0x{:X}", dev_handle);
92
93 IPC::ResponseBuilder rb{ctx, 2, 1};
94 rb.Push(RESULT_SUCCESS);
95 rb.PushCopyObjects(activate_event);
96 }
97
98 void AttachDeactivateEvent(Kernel::HLERequestContext& ctx) {
99 IPC::RequestParser rp{ctx};
100 const u64 dev_handle = rp.Pop<u64>();
101 NGLOG_WARNING(Service_NFP, "(STUBBED) called, dev_handle=0x{:X}", dev_handle);
102
103 IPC::ResponseBuilder rb{ctx, 2, 1};
104 rb.Push(RESULT_SUCCESS);
105 rb.PushCopyObjects(deactivate_event);
106 }
107
108 void GetState(Kernel::HLERequestContext& ctx) {
109 NGLOG_WARNING(Service_NFP, "(STUBBED) called");
110 IPC::ResponseBuilder rb{ctx, 3};
111 rb.Push(RESULT_SUCCESS);
112 rb.Push<u32>(static_cast<u32>(state));
113 }
114
115 void GetDeviceState(Kernel::HLERequestContext& ctx) {
116 NGLOG_WARNING(Service_NFP, "(STUBBED) called");
117 IPC::ResponseBuilder rb{ctx, 3};
118 rb.Push(RESULT_SUCCESS);
119 rb.Push<u32>(static_cast<u32>(device_state));
120 }
121
122 void GetNpadId(Kernel::HLERequestContext& ctx) {
123 IPC::RequestParser rp{ctx};
124 const u64 dev_handle = rp.Pop<u64>();
125 NGLOG_WARNING(Service_NFP, "(STUBBED) called, dev_handle=0x{:X}", dev_handle);
126 IPC::ResponseBuilder rb{ctx, 3};
127 rb.Push(RESULT_SUCCESS);
128 rb.Push<u32>(npad_id);
129 }
130
131 void AttachAvailabilityChangeEvent(Kernel::HLERequestContext& ctx) {
132 IPC::RequestParser rp{ctx};
133 const u64 dev_handle = rp.Pop<u64>();
134 NGLOG_WARNING(Service_NFP, "(STUBBED) called, dev_handle=0x{:X}", dev_handle);
135
136 IPC::ResponseBuilder rb{ctx, 2, 1};
137 rb.Push(RESULT_SUCCESS);
138 rb.PushCopyObjects(availability_change_event);
139 }
140
141 const u64 device_handle{0xDEAD};
142 const HID::ControllerID npad_id{HID::Controller_Player1};
143 State state{State::NonInitialized};
144 DeviceState device_state{DeviceState::Initialized};
145 Kernel::SharedPtr<Kernel::Event> activate_event;
146 Kernel::SharedPtr<Kernel::Event> deactivate_event;
147 Kernel::SharedPtr<Kernel::Event> availability_change_event;
54}; 148};
55 149
56void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) { 150void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) {
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index af18c2d81..2cda1e63e 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -168,13 +168,22 @@ enum class SubOp : u64 {
168 Min = 0x8, 168 Min = 0x8,
169}; 169};
170 170
171enum class FloatRoundingOp : u64 { 171enum class F2iRoundingOp : u64 {
172 None = 0, 172 None = 0,
173 Floor = 1, 173 Floor = 1,
174 Ceil = 2, 174 Ceil = 2,
175 Trunc = 3, 175 Trunc = 3,
176}; 176};
177 177
178enum class F2fRoundingOp : u64 {
179 None = 0,
180 Pass = 3,
181 Round = 8,
182 Floor = 9,
183 Ceil = 10,
184 Trunc = 11,
185};
186
178enum class UniformType : u64 { 187enum class UniformType : u64 {
179 UnsignedByte = 0, 188 UnsignedByte = 0,
180 SignedByte = 1, 189 SignedByte = 1,
@@ -314,11 +323,11 @@ union Instruction {
314 BitField<50, 1, u64> saturate_a; 323 BitField<50, 1, u64> saturate_a;
315 324
316 union { 325 union {
317 BitField<39, 2, FloatRoundingOp> rounding; 326 BitField<39, 2, F2iRoundingOp> rounding;
318 } f2i; 327 } f2i;
319 328
320 union { 329 union {
321 BitField<39, 4, u64> rounding; 330 BitField<39, 4, F2fRoundingOp> rounding;
322 } f2f; 331 } f2f;
323 } conversion; 332 } conversion;
324 333
@@ -390,6 +399,9 @@ class OpCode {
390public: 399public:
391 enum class Id { 400 enum class Id {
392 KIL, 401 KIL,
402 BFE_C,
403 BFE_R,
404 BFE_IMM,
393 BRA, 405 BRA,
394 LD_A, 406 LD_A,
395 LD_C, 407 LD_C,
@@ -444,6 +456,9 @@ public:
444 FMNMX_C, 456 FMNMX_C,
445 FMNMX_R, 457 FMNMX_R,
446 FMNMX_IMM, 458 FMNMX_IMM,
459 IMNMX_C,
460 IMNMX_R,
461 IMNMX_IMM,
447 FSETP_C, // Set Predicate 462 FSETP_C, // Set Predicate
448 FSETP_R, 463 FSETP_R,
449 FSETP_IMM, 464 FSETP_IMM,
@@ -454,6 +469,10 @@ public:
454 ISETP_IMM, 469 ISETP_IMM,
455 ISETP_R, 470 ISETP_R,
456 PSETP, 471 PSETP,
472 XMAD_IMM,
473 XMAD_CR,
474 XMAD_RC,
475 XMAD_RR,
457 }; 476 };
458 477
459 enum class Type { 478 enum class Type {
@@ -565,6 +584,9 @@ private:
565 std::vector<Matcher> table = { 584 std::vector<Matcher> table = {
566#define INST(bitstring, op, type, name) Detail::GetMatcher(bitstring, op, type, name) 585#define INST(bitstring, op, type, name) Detail::GetMatcher(bitstring, op, type, name)
567 INST("111000110011----", Id::KIL, Type::Flow, "KIL"), 586 INST("111000110011----", Id::KIL, Type::Flow, "KIL"),
587 INST("0100110000000---", Id::BFE_C, Type::Flow, "BFE_C"),
588 INST("0101110000000---", Id::BFE_R, Type::Flow, "BFE_R"),
589 INST("0011100-00000---", Id::BFE_IMM, Type::Flow, "BFE_IMM"),
568 INST("111000100100----", Id::BRA, Type::Flow, "BRA"), 590 INST("111000100100----", Id::BRA, Type::Flow, "BRA"),
569 INST("1110111111011---", Id::LD_A, Type::Memory, "LD_A"), 591 INST("1110111111011---", Id::LD_A, Type::Memory, "LD_A"),
570 INST("1110111110010---", Id::LD_C, Type::Memory, "LD_C"), 592 INST("1110111110010---", Id::LD_C, Type::Memory, "LD_C"),
@@ -606,6 +628,9 @@ private:
606 INST("0100110001100---", Id::FMNMX_C, Type::Arithmetic, "FMNMX_C"), 628 INST("0100110001100---", Id::FMNMX_C, Type::Arithmetic, "FMNMX_C"),
607 INST("0101110001100---", Id::FMNMX_R, Type::Arithmetic, "FMNMX_R"), 629 INST("0101110001100---", Id::FMNMX_R, Type::Arithmetic, "FMNMX_R"),
608 INST("0011100-01100---", Id::FMNMX_IMM, Type::Arithmetic, "FMNMX_IMM"), 630 INST("0011100-01100---", Id::FMNMX_IMM, Type::Arithmetic, "FMNMX_IMM"),
631 INST("0100110000100---", Id::IMNMX_C, Type::Arithmetic, "FMNMX_IMM"),
632 INST("0101110000100---", Id::IMNMX_R, Type::Arithmetic, "FMNMX_IMM"),
633 INST("0011100-00100---", Id::IMNMX_IMM, Type::Arithmetic, "FMNMX_IMM"),
609 INST("000001----------", Id::LOP32I, Type::Logic, "LOP32I"), 634 INST("000001----------", Id::LOP32I, Type::Logic, "LOP32I"),
610 INST("0100110001001---", Id::SHL_C, Type::Shift, "SHL_C"), 635 INST("0100110001001---", Id::SHL_C, Type::Shift, "SHL_C"),
611 INST("0101110001001---", Id::SHL_R, Type::Shift, "SHL_R"), 636 INST("0101110001001---", Id::SHL_R, Type::Shift, "SHL_R"),
@@ -629,6 +654,10 @@ private:
629 INST("010110110110----", Id::ISETP_R, Type::IntegerSetPredicate, "ISETP_R"), 654 INST("010110110110----", Id::ISETP_R, Type::IntegerSetPredicate, "ISETP_R"),
630 INST("0011011-0110----", Id::ISETP_IMM, Type::IntegerSetPredicate, "ISETP_IMM"), 655 INST("0011011-0110----", Id::ISETP_IMM, Type::IntegerSetPredicate, "ISETP_IMM"),
631 INST("0101000010010---", Id::PSETP, Type::PredicateSetPredicate, "PSETP"), 656 INST("0101000010010---", Id::PSETP, Type::PredicateSetPredicate, "PSETP"),
657 INST("0011011-00------", Id::XMAD_IMM, Type::Arithmetic, "XMAD_IMM"),
658 INST("0100111---------", Id::XMAD_CR, Type::Arithmetic, "XMAD_CR"),
659 INST("010100010-------", Id::XMAD_RC, Type::Arithmetic, "XMAD_RC"),
660 INST("0101101100------", Id::XMAD_RR, Type::Arithmetic, "XMAD_RR"),
632 }; 661 };
633#undef INST 662#undef INST
634 std::stable_sort(table.begin(), table.end(), [](const auto& a, const auto& b) { 663 std::stable_sort(table.begin(), table.end(), [](const auto& a, const auto& b) {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index b23b8fb29..2e90ebcf4 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -681,6 +681,14 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, GLuint program,
681 Surface surface = res_cache.GetTextureSurface(texture); 681 Surface surface = res_cache.GetTextureSurface(texture);
682 if (surface != nullptr) { 682 if (surface != nullptr) {
683 state.texture_units[current_bindpoint].texture_2d = surface->texture.handle; 683 state.texture_units[current_bindpoint].texture_2d = surface->texture.handle;
684 state.texture_units[current_bindpoint].swizzle.r =
685 MaxwellToGL::SwizzleSource(texture.tic.x_source);
686 state.texture_units[current_bindpoint].swizzle.g =
687 MaxwellToGL::SwizzleSource(texture.tic.y_source);
688 state.texture_units[current_bindpoint].swizzle.b =
689 MaxwellToGL::SwizzleSource(texture.tic.z_source);
690 state.texture_units[current_bindpoint].swizzle.a =
691 MaxwellToGL::SwizzleSource(texture.tic.w_source);
684 } else { 692 } else {
685 // Can occur when texture addr is null or its memory is unmapped/invalid 693 // Can occur when texture addr is null or its memory is unmapped/invalid
686 state.texture_units[current_bindpoint].texture_2d = 0; 694 state.texture_units[current_bindpoint].texture_2d = 0;
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 3067ce3b3..8e249584f 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -1056,10 +1056,27 @@ private:
1056 break; 1056 break;
1057 } 1057 }
1058 case OpCode::Id::F2F_R: { 1058 case OpCode::Id::F2F_R: {
1059 // TODO(Subv): Implement rounding operations.
1060 ASSERT_MSG(instr.conversion.f2f.rounding == 0, "Unimplemented rounding operation");
1061 std::string op_a = regs.GetRegisterAsFloat(instr.gpr20); 1059 std::string op_a = regs.GetRegisterAsFloat(instr.gpr20);
1062 1060
1061 switch (instr.conversion.f2f.rounding) {
1062 case Tegra::Shader::F2fRoundingOp::None:
1063 break;
1064 case Tegra::Shader::F2fRoundingOp::Floor:
1065 op_a = "floor(" + op_a + ')';
1066 break;
1067 case Tegra::Shader::F2fRoundingOp::Ceil:
1068 op_a = "ceil(" + op_a + ')';
1069 break;
1070 case Tegra::Shader::F2fRoundingOp::Trunc:
1071 op_a = "trunc(" + op_a + ')';
1072 break;
1073 default:
1074 NGLOG_CRITICAL(HW_GPU, "Unimplemented f2f rounding mode {}",
1075 static_cast<u32>(instr.conversion.f2f.rounding.Value()));
1076 UNREACHABLE();
1077 break;
1078 }
1079
1063 if (instr.conversion.abs_a) { 1080 if (instr.conversion.abs_a) {
1064 op_a = "abs(" + op_a + ')'; 1081 op_a = "abs(" + op_a + ')';
1065 } 1082 }
@@ -1074,17 +1091,16 @@ private:
1074 op_a = "abs(" + op_a + ')'; 1091 op_a = "abs(" + op_a + ')';
1075 } 1092 }
1076 1093
1077 using Tegra::Shader::FloatRoundingOp;
1078 switch (instr.conversion.f2i.rounding) { 1094 switch (instr.conversion.f2i.rounding) {
1079 case FloatRoundingOp::None: 1095 case Tegra::Shader::F2iRoundingOp::None:
1080 break; 1096 break;
1081 case FloatRoundingOp::Floor: 1097 case Tegra::Shader::F2iRoundingOp::Floor:
1082 op_a = "floor(" + op_a + ')'; 1098 op_a = "floor(" + op_a + ')';
1083 break; 1099 break;
1084 case FloatRoundingOp::Ceil: 1100 case Tegra::Shader::F2iRoundingOp::Ceil:
1085 op_a = "ceil(" + op_a + ')'; 1101 op_a = "ceil(" + op_a + ')';
1086 break; 1102 break;
1087 case FloatRoundingOp::Trunc: 1103 case Tegra::Shader::F2iRoundingOp::Trunc:
1088 op_a = "trunc(" + op_a + ')'; 1104 op_a = "trunc(" + op_a + ')';
1089 break; 1105 break;
1090 default: 1106 default:
@@ -1112,13 +1128,11 @@ private:
1112 break; 1128 break;
1113 } 1129 }
1114 case OpCode::Type::Memory: { 1130 case OpCode::Type::Memory: {
1115 const Attribute::Index attribute = instr.attribute.fmt20.index;
1116
1117 switch (opcode->GetId()) { 1131 switch (opcode->GetId()) {
1118 case OpCode::Id::LD_A: { 1132 case OpCode::Id::LD_A: {
1119 ASSERT_MSG(instr.attribute.fmt20.size == 0, "untested"); 1133 ASSERT_MSG(instr.attribute.fmt20.size == 0, "untested");
1120 regs.SetRegisterToInputAttibute(instr.gpr0, instr.attribute.fmt20.element, 1134 regs.SetRegisterToInputAttibute(instr.gpr0, instr.attribute.fmt20.element,
1121 attribute); 1135 instr.attribute.fmt20.index);
1122 break; 1136 break;
1123 } 1137 }
1124 case OpCode::Id::LD_C: { 1138 case OpCode::Id::LD_C: {
@@ -1150,12 +1164,11 @@ private:
1150 } 1164 }
1151 case OpCode::Id::ST_A: { 1165 case OpCode::Id::ST_A: {
1152 ASSERT_MSG(instr.attribute.fmt20.size == 0, "untested"); 1166 ASSERT_MSG(instr.attribute.fmt20.size == 0, "untested");
1153 regs.SetOutputAttributeToRegister(attribute, instr.attribute.fmt20.element, 1167 regs.SetOutputAttributeToRegister(instr.attribute.fmt20.index,
1154 instr.gpr0); 1168 instr.attribute.fmt20.element, instr.gpr0);
1155 break; 1169 break;
1156 } 1170 }
1157 case OpCode::Id::TEX: { 1171 case OpCode::Id::TEX: {
1158 ASSERT_MSG(instr.attribute.fmt20.size == 4, "untested");
1159 const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); 1172 const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
1160 const std::string op_b = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); 1173 const std::string op_b = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
1161 const std::string sampler = GetSampler(instr.sampler); 1174 const std::string sampler = GetSampler(instr.sampler);
@@ -1168,7 +1181,7 @@ private:
1168 const std::string texture = "texture(" + sampler + ", coords)"; 1181 const std::string texture = "texture(" + sampler + ", coords)";
1169 1182
1170 size_t dest_elem{}; 1183 size_t dest_elem{};
1171 for (size_t elem = 0; elem < instr.attribute.fmt20.size; ++elem) { 1184 for (size_t elem = 0; elem < 4; ++elem) {
1172 if (!instr.tex.IsComponentEnabled(elem)) { 1185 if (!instr.tex.IsComponentEnabled(elem)) {
1173 // Skip disabled components 1186 // Skip disabled components
1174 continue; 1187 continue;
@@ -1181,7 +1194,6 @@ private:
1181 break; 1194 break;
1182 } 1195 }
1183 case OpCode::Id::TEXS: { 1196 case OpCode::Id::TEXS: {
1184 ASSERT_MSG(instr.attribute.fmt20.size == 4, "untested");
1185 const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); 1197 const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
1186 const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20); 1198 const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20);
1187 const std::string sampler = GetSampler(instr.sampler); 1199 const std::string sampler = GetSampler(instr.sampler);
@@ -1278,16 +1290,17 @@ private:
1278 } 1290 }
1279 case OpCode::Type::IntegerSetPredicate: { 1291 case OpCode::Type::IntegerSetPredicate: {
1280 std::string op_a = regs.GetRegisterAsInteger(instr.gpr8, 0, instr.isetp.is_signed); 1292 std::string op_a = regs.GetRegisterAsInteger(instr.gpr8, 0, instr.isetp.is_signed);
1293 std::string op_b;
1281 1294
1282 std::string op_b{}; 1295 if (instr.is_b_imm) {
1283 1296 op_b += '(' + std::to_string(instr.alu.GetSignedImm20_20()) + ')';
1284 ASSERT_MSG(!instr.is_b_imm, "ISETP_IMM not implemented");
1285
1286 if (instr.is_b_gpr) {
1287 op_b += regs.GetRegisterAsInteger(instr.gpr20, 0, instr.isetp.is_signed);
1288 } else { 1297 } else {
1289 op_b += regs.GetUniform(instr.cbuf34.index, instr.cbuf34.offset, 1298 if (instr.is_b_gpr) {
1290 GLSLRegister::Type::Integer); 1299 op_b += regs.GetRegisterAsInteger(instr.gpr20, 0, instr.isetp.is_signed);
1300 } else {
1301 op_b += regs.GetUniform(instr.cbuf34.index, instr.cbuf34.offset,
1302 GLSLRegister::Type::Integer);
1303 }
1291 } 1304 }
1292 1305
1293 using Tegra::Shader::Pred; 1306 using Tegra::Shader::Pred;
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index f91dfe36a..44f0c8a01 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -50,6 +50,10 @@ OpenGLState::OpenGLState() {
50 for (auto& texture_unit : texture_units) { 50 for (auto& texture_unit : texture_units) {
51 texture_unit.texture_2d = 0; 51 texture_unit.texture_2d = 0;
52 texture_unit.sampler = 0; 52 texture_unit.sampler = 0;
53 texture_unit.swizzle.r = GL_RED;
54 texture_unit.swizzle.g = GL_GREEN;
55 texture_unit.swizzle.b = GL_BLUE;
56 texture_unit.swizzle.a = GL_ALPHA;
53 } 57 }
54 58
55 lighting_lut.texture_buffer = 0; 59 lighting_lut.texture_buffer = 0;
@@ -200,6 +204,15 @@ void OpenGLState::Apply() const {
200 if (texture_units[i].sampler != cur_state.texture_units[i].sampler) { 204 if (texture_units[i].sampler != cur_state.texture_units[i].sampler) {
201 glBindSampler(i, texture_units[i].sampler); 205 glBindSampler(i, texture_units[i].sampler);
202 } 206 }
207 // Update the texture swizzle
208 if (texture_units[i].swizzle.r != cur_state.texture_units[i].swizzle.r ||
209 texture_units[i].swizzle.g != cur_state.texture_units[i].swizzle.g ||
210 texture_units[i].swizzle.b != cur_state.texture_units[i].swizzle.b ||
211 texture_units[i].swizzle.a != cur_state.texture_units[i].swizzle.a) {
212 std::array<GLint, 4> mask = {texture_units[i].swizzle.r, texture_units[i].swizzle.g,
213 texture_units[i].swizzle.b, texture_units[i].swizzle.a};
214 glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, mask.data());
215 }
203 } 216 }
204 217
205 // Constbuffers 218 // Constbuffers
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index 75c08e645..839e50e93 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -85,6 +85,12 @@ public:
85 struct { 85 struct {
86 GLuint texture_2d; // GL_TEXTURE_BINDING_2D 86 GLuint texture_2d; // GL_TEXTURE_BINDING_2D
87 GLuint sampler; // GL_SAMPLER_BINDING 87 GLuint sampler; // GL_SAMPLER_BINDING
88 struct {
89 GLint r; // GL_TEXTURE_SWIZZLE_R
90 GLint g; // GL_TEXTURE_SWIZZLE_G
91 GLint b; // GL_TEXTURE_SWIZZLE_B
92 GLint a; // GL_TEXTURE_SWIZZLE_A
93 } swizzle;
88 } texture_units[32]; 94 } texture_units[32];
89 95
90 struct { 96 struct {
diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h
index cf11983cf..2155fb019 100644
--- a/src/video_core/renderer_opengl/maxwell_to_gl.h
+++ b/src/video_core/renderer_opengl/maxwell_to_gl.h
@@ -180,4 +180,25 @@ inline GLenum BlendFunc(Maxwell::Blend::Factor factor) {
180 return {}; 180 return {};
181} 181}
182 182
183inline GLenum SwizzleSource(Tegra::Texture::SwizzleSource source) {
184 switch (source) {
185 case Tegra::Texture::SwizzleSource::Zero:
186 return GL_ZERO;
187 case Tegra::Texture::SwizzleSource::R:
188 return GL_RED;
189 case Tegra::Texture::SwizzleSource::G:
190 return GL_GREEN;
191 case Tegra::Texture::SwizzleSource::B:
192 return GL_BLUE;
193 case Tegra::Texture::SwizzleSource::A:
194 return GL_ALPHA;
195 case Tegra::Texture::SwizzleSource::OneInt:
196 case Tegra::Texture::SwizzleSource::OneFloat:
197 return GL_ONE;
198 }
199 NGLOG_CRITICAL(Render_OpenGL, "Unimplemented swizzle source={}", static_cast<u32>(source));
200 UNREACHABLE();
201 return {};
202}
203
183} // namespace MaxwellToGL 204} // namespace MaxwellToGL
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 3440d2190..f33766bfd 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -316,6 +316,7 @@ void RendererOpenGL::DrawScreenTriangles(const ScreenInfo& screen_info, float x,
316 }}; 316 }};
317 317
318 state.texture_units[0].texture_2d = screen_info.display_texture; 318 state.texture_units[0].texture_2d = screen_info.display_texture;
319 state.texture_units[0].swizzle = {GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA};
319 state.Apply(); 320 state.Apply();
320 321
321 glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices.data()); 322 glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices.data());
diff --git a/src/video_core/textures/texture.h b/src/video_core/textures/texture.h
index f48ca30b8..a17eaf19d 100644
--- a/src/video_core/textures/texture.h
+++ b/src/video_core/textures/texture.h
@@ -122,6 +122,17 @@ enum class ComponentType : u32 {
122 FLOAT = 7 122 FLOAT = 7
123}; 123};
124 124
125enum class SwizzleSource : u32 {
126 Zero = 0,
127
128 R = 2,
129 G = 3,
130 B = 4,
131 A = 5,
132 OneInt = 6,
133 OneFloat = 7,
134};
135
125union TextureHandle { 136union TextureHandle {
126 u32 raw; 137 u32 raw;
127 BitField<0, 20, u32> tic_id; 138 BitField<0, 20, u32> tic_id;
@@ -139,6 +150,11 @@ struct TICEntry {
139 BitField<10, 3, ComponentType> g_type; 150 BitField<10, 3, ComponentType> g_type;
140 BitField<13, 3, ComponentType> b_type; 151 BitField<13, 3, ComponentType> b_type;
141 BitField<16, 3, ComponentType> a_type; 152 BitField<16, 3, ComponentType> a_type;
153
154 BitField<19, 3, SwizzleSource> x_source;
155 BitField<22, 3, SwizzleSource> y_source;
156 BitField<25, 3, SwizzleSource> z_source;
157 BitField<28, 3, SwizzleSource> w_source;
142 }; 158 };
143 u32 address_low; 159 u32 address_low;
144 union { 160 union {