summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/common/bit_field.h7
-rw-r--r--src/video_core/engines/maxwell_3d.cpp4
-rw-r--r--src/video_core/engines/maxwell_3d.h48
-rw-r--r--src/video_core/engines/shader_bytecode.h43
-rw-r--r--src/video_core/rasterizer_interface.h2
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp27
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h2
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp197
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.cpp6
-rw-r--r--src/video_core/renderer_opengl/maxwell_to_gl.h64
10 files changed, 320 insertions, 80 deletions
diff --git a/src/common/bit_field.h b/src/common/bit_field.h
index 5638bdbba..65e357dec 100644
--- a/src/common/bit_field.h
+++ b/src/common/bit_field.h
@@ -192,11 +192,6 @@ private:
192 static_assert(position < 8 * sizeof(T), "Invalid position"); 192 static_assert(position < 8 * sizeof(T), "Invalid position");
193 static_assert(bits <= 8 * sizeof(T), "Invalid number of bits"); 193 static_assert(bits <= 8 * sizeof(T), "Invalid number of bits");
194 static_assert(bits > 0, "Invalid number of bits"); 194 static_assert(bits > 0, "Invalid number of bits");
195 static_assert(std::is_pod<T>::value, "Invalid base type"); 195 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable in a BitField");
196}; 196};
197#pragma pack() 197#pragma pack()
198
199#if (__GNUC__ >= 5) || defined(__clang__) || defined(_MSC_VER)
200static_assert(std::is_trivially_copyable<BitField<0, 1, unsigned>>::value,
201 "BitField must be trivially copyable");
202#endif
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index 85b50c9b3..a2f162602 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -74,8 +74,6 @@ void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) {
74 74
75 regs.reg_array[method] = value; 75 regs.reg_array[method] = value;
76 76
77#define MAXWELL3D_REG_INDEX(field_name) (offsetof(Regs, field_name) / sizeof(u32))
78
79 switch (method) { 77 switch (method) {
80 case MAXWELL3D_REG_INDEX(code_address.code_address_high): 78 case MAXWELL3D_REG_INDEX(code_address.code_address_high):
81 case MAXWELL3D_REG_INDEX(code_address.code_address_low): { 79 case MAXWELL3D_REG_INDEX(code_address.code_address_low): {
@@ -136,7 +134,7 @@ void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) {
136 break; 134 break;
137 } 135 }
138 136
139#undef MAXWELL3D_REG_INDEX 137 VideoCore::g_renderer->Rasterizer()->NotifyMaxwellRegisterChanged(method);
140 138
141 if (debug_context) { 139 if (debug_context) {
142 debug_context->OnEvent(Tegra::DebugContext::Event::MaxwellCommandProcessed, nullptr); 140 debug_context->OnEvent(Tegra::DebugContext::Event::MaxwellCommandProcessed, nullptr);
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 2b45ffed7..b379d8057 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -20,6 +20,9 @@
20namespace Tegra { 20namespace Tegra {
21namespace Engines { 21namespace Engines {
22 22
23#define MAXWELL3D_REG_INDEX(field_name) \
24 (offsetof(Tegra::Engines::Maxwell3D::Regs, field_name) / sizeof(u32))
25
23class Maxwell3D final { 26class Maxwell3D final {
24public: 27public:
25 explicit Maxwell3D(MemoryManager& memory_manager); 28 explicit Maxwell3D(MemoryManager& memory_manager);
@@ -254,6 +257,46 @@ public:
254 UnsignedInt = 0x2, 257 UnsignedInt = 0x2,
255 }; 258 };
256 259
260 struct Blend {
261 enum class Equation : u32 {
262 Add = 1,
263 Subtract = 2,
264 ReverseSubtract = 3,
265 Min = 4,
266 Max = 5,
267 };
268
269 enum class Factor : u32 {
270 Zero = 0x1,
271 One = 0x2,
272 SourceColor = 0x3,
273 OneMinusSourceColor = 0x4,
274 SourceAlpha = 0x5,
275 OneMinusSourceAlpha = 0x6,
276 DestAlpha = 0x7,
277 OneMinusDestAlpha = 0x8,
278 DestColor = 0x9,
279 OneMinusDestColor = 0xa,
280 SourceAlphaSaturate = 0xb,
281 Source1Color = 0x10,
282 OneMinusSource1Color = 0x11,
283 Source1Alpha = 0x12,
284 OneMinusSource1Alpha = 0x13,
285 ConstantColor = 0x61,
286 OneMinusConstantColor = 0x62,
287 ConstantAlpha = 0x63,
288 OneMinusConstantAlpha = 0x64,
289 };
290
291 u32 separate_alpha;
292 Equation equation_rgb;
293 Factor factor_source_rgb;
294 Factor factor_dest_rgb;
295 Equation equation_a;
296 Factor factor_source_a;
297 Factor factor_dest_a;
298 };
299
257 union { 300 union {
258 struct { 301 struct {
259 INSERT_PADDING_WORDS(0x200); 302 INSERT_PADDING_WORDS(0x200);
@@ -451,7 +494,9 @@ public:
451 } 494 }
452 } vertex_array[NumVertexArrays]; 495 } vertex_array[NumVertexArrays];
453 496
454 INSERT_PADDING_WORDS(0x40); 497 Blend blend;
498
499 INSERT_PADDING_WORDS(0x39);
455 500
456 struct { 501 struct {
457 u32 limit_high; 502 u32 limit_high;
@@ -616,6 +661,7 @@ ASSERT_REG_POSITION(draw, 0x585);
616ASSERT_REG_POSITION(index_array, 0x5F2); 661ASSERT_REG_POSITION(index_array, 0x5F2);
617ASSERT_REG_POSITION(query, 0x6C0); 662ASSERT_REG_POSITION(query, 0x6C0);
618ASSERT_REG_POSITION(vertex_array[0], 0x700); 663ASSERT_REG_POSITION(vertex_array[0], 0x700);
664ASSERT_REG_POSITION(blend, 0x780);
619ASSERT_REG_POSITION(vertex_array_limit[0], 0x7C0); 665ASSERT_REG_POSITION(vertex_array_limit[0], 0x7C0);
620ASSERT_REG_POSITION(shader_config[0], 0x800); 666ASSERT_REG_POSITION(shader_config[0], 0x800);
621ASSERT_REG_POSITION(const_buffer, 0x8E0); 667ASSERT_REG_POSITION(const_buffer, 0x8E0);
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index eff0c35a1..ed66d893a 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <cstring>
7#include <map> 8#include <map>
8#include <string> 9#include <string>
9#include "common/bit_field.h" 10#include "common/bit_field.h"
@@ -12,14 +13,10 @@ namespace Tegra {
12namespace Shader { 13namespace Shader {
13 14
14struct Register { 15struct Register {
15 Register() = default; 16 constexpr Register() = default;
16 17
17 constexpr Register(u64 value) : value(value) {} 18 constexpr Register(u64 value) : value(value) {}
18 19
19 constexpr u64 GetIndex() const {
20 return value;
21 }
22
23 constexpr operator u64() const { 20 constexpr operator u64() const {
24 return value; 21 return value;
25 } 22 }
@@ -43,13 +40,13 @@ struct Register {
43 } 40 }
44 41
45private: 42private:
46 u64 value; 43 u64 value{};
47}; 44};
48 45
49union Attribute { 46union Attribute {
50 Attribute() = default; 47 Attribute() = default;
51 48
52 constexpr Attribute(u64 value) : value(value) {} 49 constexpr explicit Attribute(u64 value) : value(value) {}
53 50
54 enum class Index : u64 { 51 enum class Index : u64 {
55 Position = 7, 52 Position = 7,
@@ -68,7 +65,20 @@ union Attribute {
68 } fmt28; 65 } fmt28;
69 66
70 BitField<39, 8, u64> reg; 67 BitField<39, 8, u64> reg;
71 u64 value; 68 u64 value{};
69};
70
71union Sampler {
72 Sampler() = default;
73
74 constexpr explicit Sampler(u64 value) : value(value) {}
75
76 enum class Index : u64 {
77 Sampler_0 = 8,
78 };
79
80 BitField<36, 13, Index> index;
81 u64 value{};
72}; 82};
73 83
74union Uniform { 84union Uniform {
@@ -238,7 +248,7 @@ union OpCode {
238 BitField<55, 9, Id> op3; 248 BitField<55, 9, Id> op3;
239 BitField<52, 12, Id> op4; 249 BitField<52, 12, Id> op4;
240 BitField<51, 13, Id> op5; 250 BitField<51, 13, Id> op5;
241 u64 value; 251 u64 value{};
242}; 252};
243static_assert(sizeof(OpCode) == 0x8, "Incorrect structure size"); 253static_assert(sizeof(OpCode) == 0x8, "Incorrect structure size");
244 254
@@ -280,6 +290,7 @@ enum class SubOp : u64 {
280 Lg2 = 0x3, 290 Lg2 = 0x3,
281 Rcp = 0x4, 291 Rcp = 0x4,
282 Rsq = 0x5, 292 Rsq = 0x5,
293 Min = 0x8,
283}; 294};
284 295
285union Instruction { 296union Instruction {
@@ -295,15 +306,25 @@ union Instruction {
295 BitField<20, 8, Register> gpr20; 306 BitField<20, 8, Register> gpr20;
296 BitField<20, 7, SubOp> sub_op; 307 BitField<20, 7, SubOp> sub_op;
297 BitField<28, 8, Register> gpr28; 308 BitField<28, 8, Register> gpr28;
298 BitField<36, 13, u64> imm36;
299 BitField<39, 8, Register> gpr39; 309 BitField<39, 8, Register> gpr39;
300 310
301 union { 311 union {
312 BitField<20, 19, u64> imm20;
302 BitField<45, 1, u64> negate_b; 313 BitField<45, 1, u64> negate_b;
303 BitField<46, 1, u64> abs_a; 314 BitField<46, 1, u64> abs_a;
304 BitField<48, 1, u64> negate_a; 315 BitField<48, 1, u64> negate_a;
305 BitField<49, 1, u64> abs_b; 316 BitField<49, 1, u64> abs_b;
306 BitField<50, 1, u64> abs_d; 317 BitField<50, 1, u64> abs_d;
318 BitField<56, 1, u64> negate_imm;
319
320 float GetImm20() const {
321 float result{};
322 u32 imm{static_cast<u32>(imm20)};
323 imm <<= 12;
324 imm |= negate_imm ? 0x80000000 : 0;
325 std::memcpy(&result, &imm, sizeof(imm));
326 return result;
327 }
307 } alu; 328 } alu;
308 329
309 union { 330 union {
@@ -311,11 +332,13 @@ union Instruction {
311 BitField<49, 1, u64> negate_c; 332 BitField<49, 1, u64> negate_c;
312 } ffma; 333 } ffma;
313 334
335 BitField<61, 1, u64> is_b_imm;
314 BitField<60, 1, u64> is_b_gpr; 336 BitField<60, 1, u64> is_b_gpr;
315 BitField<59, 1, u64> is_c_gpr; 337 BitField<59, 1, u64> is_c_gpr;
316 338
317 Attribute attribute; 339 Attribute attribute;
318 Uniform uniform; 340 Uniform uniform;
341 Sampler sampler;
319 342
320 u64 hex; 343 u64 hex;
321}; 344};
diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h
index 35d262189..36629dd11 100644
--- a/src/video_core/rasterizer_interface.h
+++ b/src/video_core/rasterizer_interface.h
@@ -19,7 +19,7 @@ public:
19 virtual void DrawArrays() = 0; 19 virtual void DrawArrays() = 0;
20 20
21 /// Notify rasterizer that the specified Maxwell register has been changed 21 /// Notify rasterizer that the specified Maxwell register has been changed
22 virtual void NotifyMaxwellRegisterChanged(u32 id) = 0; 22 virtual void NotifyMaxwellRegisterChanged(u32 method) = 0;
23 23
24 /// Notify rasterizer that all caches should be flushed to Switch memory 24 /// Notify rasterizer that all caches should be flushed to Switch memory
25 virtual void FlushAll() = 0; 25 virtual void FlushAll() = 0;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 75b4031a7..7b6240e65 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -446,7 +446,32 @@ void RasterizerOpenGL::BindTextures() {
446 } 446 }
447} 447}
448 448
449void RasterizerOpenGL::NotifyMaxwellRegisterChanged(u32 id) {} 449void RasterizerOpenGL::NotifyMaxwellRegisterChanged(u32 method) {
450 const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs;
451 switch (method) {
452 case MAXWELL3D_REG_INDEX(blend.separate_alpha):
453 ASSERT_MSG(false, "unimplemented");
454 break;
455 case MAXWELL3D_REG_INDEX(blend.equation_rgb):
456 state.blend.rgb_equation = MaxwellToGL::BlendEquation(regs.blend.equation_rgb);
457 break;
458 case MAXWELL3D_REG_INDEX(blend.factor_source_rgb):
459 state.blend.src_rgb_func = MaxwellToGL::BlendFunc(regs.blend.factor_source_rgb);
460 break;
461 case MAXWELL3D_REG_INDEX(blend.factor_dest_rgb):
462 state.blend.dst_rgb_func = MaxwellToGL::BlendFunc(regs.blend.factor_dest_rgb);
463 break;
464 case MAXWELL3D_REG_INDEX(blend.equation_a):
465 state.blend.a_equation = MaxwellToGL::BlendEquation(regs.blend.equation_a);
466 break;
467 case MAXWELL3D_REG_INDEX(blend.factor_source_a):
468 state.blend.src_a_func = MaxwellToGL::BlendFunc(regs.blend.factor_source_a);
469 break;
470 case MAXWELL3D_REG_INDEX(blend.factor_dest_a):
471 state.blend.dst_a_func = MaxwellToGL::BlendFunc(regs.blend.factor_dest_a);
472 break;
473 }
474}
450 475
451void RasterizerOpenGL::FlushAll() { 476void RasterizerOpenGL::FlushAll() {
452 MICROPROFILE_SCOPE(OpenGL_CacheManagement); 477 MICROPROFILE_SCOPE(OpenGL_CacheManagement);
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index fb5d99ba2..9ece415f7 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -32,7 +32,7 @@ public:
32 ~RasterizerOpenGL() override; 32 ~RasterizerOpenGL() override;
33 33
34 void DrawArrays() override; 34 void DrawArrays() override;
35 void NotifyMaxwellRegisterChanged(u32 id) override; 35 void NotifyMaxwellRegisterChanged(u32 method) override;
36 void FlushAll() override; 36 void FlushAll() override;
37 void FlushRegion(VAddr addr, u64 size) override; 37 void FlushRegion(VAddr addr, u64 size) override;
38 void InvalidateRegion(VAddr addr, u64 size) override; 38 void InvalidateRegion(VAddr addr, u64 size) override;
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index e11711533..6233ee358 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -17,6 +17,7 @@ using Tegra::Shader::Attribute;
17using Tegra::Shader::Instruction; 17using Tegra::Shader::Instruction;
18using Tegra::Shader::OpCode; 18using Tegra::Shader::OpCode;
19using Tegra::Shader::Register; 19using Tegra::Shader::Register;
20using Tegra::Shader::Sampler;
20using Tegra::Shader::SubOp; 21using Tegra::Shader::SubOp;
21using Tegra::Shader::Uniform; 22using Tegra::Shader::Uniform;
22 23
@@ -155,23 +156,27 @@ private:
155 156
156 /// Generates code representing an input attribute register. 157 /// Generates code representing an input attribute register.
157 std::string GetInputAttribute(Attribute::Index attribute) { 158 std::string GetInputAttribute(Attribute::Index attribute) {
158 declr_input_attribute.insert(attribute); 159 switch (attribute) {
160 case Attribute::Index::Position:
161 return "position";
162 default:
163 const u32 index{static_cast<u32>(attribute) -
164 static_cast<u32>(Attribute::Index::Attribute_0)};
165 if (attribute >= Attribute::Index::Attribute_0) {
166 declr_input_attribute.insert(attribute);
167 return "input_attribute_" + std::to_string(index);
168 }
159 169
160 const u32 index{static_cast<u32>(attribute) - 170 NGLOG_CRITICAL(HW_GPU, "Unhandled input attribute: {}", index);
161 static_cast<u32>(Attribute::Index::Attribute_0)}; 171 UNREACHABLE();
162 if (attribute >= Attribute::Index::Attribute_0) {
163 return "input_attribute_" + std::to_string(index);
164 } 172 }
165
166 LOG_CRITICAL(HW_GPU, "Unhandled input attribute: 0x%02x", index);
167 UNREACHABLE();
168 } 173 }
169 174
170 /// Generates code representing an output attribute register. 175 /// Generates code representing an output attribute register.
171 std::string GetOutputAttribute(Attribute::Index attribute) { 176 std::string GetOutputAttribute(Attribute::Index attribute) {
172 switch (attribute) { 177 switch (attribute) {
173 case Attribute::Index::Position: 178 case Attribute::Index::Position:
174 return "gl_Position"; 179 return "position";
175 default: 180 default:
176 const u32 index{static_cast<u32>(attribute) - 181 const u32 index{static_cast<u32>(attribute) -
177 static_cast<u32>(Attribute::Index::Attribute_0)}; 182 static_cast<u32>(Attribute::Index::Attribute_0)};
@@ -180,22 +185,42 @@ private:
180 return "output_attribute_" + std::to_string(index); 185 return "output_attribute_" + std::to_string(index);
181 } 186 }
182 187
183 LOG_CRITICAL(HW_GPU, "Unhandled output attribute: 0x%02x", index); 188 NGLOG_CRITICAL(HW_GPU, "Unhandled output attribute: {}", index);
184 UNREACHABLE(); 189 UNREACHABLE();
185 } 190 }
186 } 191 }
187 192
193 /// Generates code representing an immediate value
194 static std::string GetImmediate(const Instruction& instr) {
195 return std::to_string(instr.alu.GetImm20());
196 }
197
188 /// Generates code representing a temporary (GPR) register. 198 /// Generates code representing a temporary (GPR) register.
189 std::string GetRegister(const Register& reg) { 199 std::string GetRegister(const Register& reg, unsigned elem = 0) {
190 return *declr_register.insert("register_" + std::to_string(reg)).first; 200 if (stage == Maxwell3D::Regs::ShaderStage::Fragment && reg < 4) {
201 // GPRs 0-3 are output color for the fragment shader
202 return std::string{"color."} + "rgba"[(reg + elem) & 3];
203 }
204
205 return *declr_register.insert("register_" + std::to_string(reg + elem)).first;
191 } 206 }
192 207
193 /// Generates code representing a uniform (C buffer) register. 208 /// Generates code representing a uniform (C buffer) register.
194 std::string GetUniform(const Uniform& reg) { 209 std::string GetUniform(const Uniform& reg) {
195 declr_const_buffers[reg.index].MarkAsUsed(reg.index, reg.offset, stage); 210 declr_const_buffers[reg.index].MarkAsUsed(static_cast<unsigned>(reg.index),
211 static_cast<unsigned>(reg.offset), stage);
196 return 'c' + std::to_string(reg.index) + '[' + std::to_string(reg.offset) + ']'; 212 return 'c' + std::to_string(reg.index) + '[' + std::to_string(reg.offset) + ']';
197 } 213 }
198 214
215 /// Generates code representing a texture sampler.
216 std::string GetSampler(const Sampler& sampler) const {
217 // TODO(Subv): Support more than just texture sampler 0
218 ASSERT_MSG(sampler.index == Sampler::Index::Sampler_0, "unsupported");
219 const unsigned index{static_cast<unsigned>(sampler.index.Value()) -
220 static_cast<unsigned>(Sampler::Index::Sampler_0)};
221 return "tex[" + std::to_string(index) + "]";
222 }
223
199 /** 224 /**
200 * Adds code that calls a subroutine. 225 * Adds code that calls a subroutine.
201 * @param subroutine the subroutine to call. 226 * @param subroutine the subroutine to call.
@@ -217,12 +242,13 @@ private:
217 * @param value the code representing the value to assign. 242 * @param value the code representing the value to assign.
218 */ 243 */
219 void SetDest(u64 elem, const std::string& reg, const std::string& value, 244 void SetDest(u64 elem, const std::string& reg, const std::string& value,
220 u64 dest_num_components, u64 value_num_components) { 245 u64 dest_num_components, u64 value_num_components, bool is_abs = false) {
221 std::string swizzle = "."; 246 std::string swizzle = ".";
222 swizzle += "xyzw"[elem]; 247 swizzle += "xyzw"[elem];
223 248
224 std::string dest = reg + (dest_num_components != 1 ? swizzle : ""); 249 std::string dest = reg + (dest_num_components != 1 ? swizzle : "");
225 std::string src = "(" + value + ")" + (value_num_components != 1 ? swizzle : ""); 250 std::string src = "(" + value + ")" + (value_num_components != 1 ? swizzle : "");
251 src = is_abs ? "abs(" + src + ")" : src;
226 252
227 shader.AddLine(dest + " = " + src + ";"); 253 shader.AddLine(dest + " = " + src + ";");
228 } 254 }
@@ -240,8 +266,6 @@ private:
240 266
241 switch (OpCode::GetInfo(instr.opcode).type) { 267 switch (OpCode::GetInfo(instr.opcode).type) {
242 case OpCode::Type::Arithmetic: { 268 case OpCode::Type::Arithmetic: {
243 ASSERT(!instr.alu.abs_d);
244
245 std::string dest = GetRegister(instr.gpr0); 269 std::string dest = GetRegister(instr.gpr0);
246 std::string op_a = instr.alu.negate_a ? "-" : ""; 270 std::string op_a = instr.alu.negate_a ? "-" : "";
247 op_a += GetRegister(instr.gpr8); 271 op_a += GetRegister(instr.gpr8);
@@ -250,63 +274,109 @@ private:
250 } 274 }
251 275
252 std::string op_b = instr.alu.negate_b ? "-" : ""; 276 std::string op_b = instr.alu.negate_b ? "-" : "";
253 if (instr.is_b_gpr) { 277
254 op_b += GetRegister(instr.gpr20); 278 if (instr.is_b_imm) {
279 op_b += GetImmediate(instr);
255 } else { 280 } else {
256 op_b += GetUniform(instr.uniform); 281 if (instr.is_b_gpr) {
282 op_b += GetRegister(instr.gpr20);
283 } else {
284 op_b += GetUniform(instr.uniform);
285 }
257 } 286 }
287
258 if (instr.alu.abs_b) { 288 if (instr.alu.abs_b) {
259 op_b = "abs(" + op_b + ")"; 289 op_b = "abs(" + op_b + ")";
260 } 290 }
261 291
262 switch (instr.opcode.EffectiveOpCode()) { 292 switch (instr.opcode.EffectiveOpCode()) {
263 case OpCode::Id::FMUL_C: 293 case OpCode::Id::FMUL_C:
264 case OpCode::Id::FMUL_R: { 294 case OpCode::Id::FMUL_R:
265 SetDest(0, dest, op_a + " * " + op_b, 1, 1); 295 case OpCode::Id::FMUL_IMM: {
296 SetDest(0, dest, op_a + " * " + op_b, 1, 1, instr.alu.abs_d);
266 break; 297 break;
267 } 298 }
268 case OpCode::Id::FADD_C: 299 case OpCode::Id::FADD_C:
269 case OpCode::Id::FADD_R: { 300 case OpCode::Id::FADD_R:
270 SetDest(0, dest, op_a + " + " + op_b, 1, 1); 301 case OpCode::Id::FADD_IMM: {
302 SetDest(0, dest, op_a + " + " + op_b, 1, 1, instr.alu.abs_d);
271 break; 303 break;
272 } 304 }
273 default: { 305 case OpCode::Id::MUFU: {
274 LOG_CRITICAL(HW_GPU, "Unhandled arithmetic instruction: 0x%02x (%s): 0x%08x", 306 switch (instr.sub_op) {
275 static_cast<unsigned>(instr.opcode.EffectiveOpCode()), 307 case SubOp::Cos:
276 OpCode::GetInfo(instr.opcode).name.c_str(), instr.hex); 308 SetDest(0, dest, "cos(" + op_a + ")", 1, 1, instr.alu.abs_d);
277 throw DecompileFail("Unhandled instruction"); 309 break;
310 case SubOp::Sin:
311 SetDest(0, dest, "sin(" + op_a + ")", 1, 1, instr.alu.abs_d);
312 break;
313 case SubOp::Ex2:
314 SetDest(0, dest, "exp2(" + op_a + ")", 1, 1, instr.alu.abs_d);
315 break;
316 case SubOp::Lg2:
317 SetDest(0, dest, "log2(" + op_a + ")", 1, 1, instr.alu.abs_d);
318 break;
319 case SubOp::Rcp:
320 SetDest(0, dest, "1.0 / " + op_a, 1, 1, instr.alu.abs_d);
321 break;
322 case SubOp::Rsq:
323 SetDest(0, dest, "inversesqrt(" + op_a + ")", 1, 1, instr.alu.abs_d);
324 break;
325 case SubOp::Min:
326 SetDest(0, dest, "min(" + op_a + "," + op_b + ")", 1, 1, instr.alu.abs_d);
327 break;
328 default:
329 NGLOG_CRITICAL(HW_GPU, "Unhandled MUFU sub op: {}",
330 static_cast<unsigned>(instr.sub_op.Value()));
331 UNREACHABLE();
332 }
278 break; 333 break;
279 } 334 }
335 default: {
336 NGLOG_CRITICAL(HW_GPU, "Unhandled arithmetic instruction: {} ({}): {}",
337 static_cast<unsigned>(instr.opcode.EffectiveOpCode()),
338 OpCode::GetInfo(instr.opcode).name, instr.hex);
339 UNREACHABLE();
340 }
280 } 341 }
281 break; 342 break;
282 } 343 }
283 case OpCode::Type::Ffma: { 344 case OpCode::Type::Ffma: {
284 ASSERT_MSG(!instr.ffma.negate_b, "untested");
285 ASSERT_MSG(!instr.ffma.negate_c, "untested");
286
287 std::string dest = GetRegister(instr.gpr0); 345 std::string dest = GetRegister(instr.gpr0);
288 std::string op_a = GetRegister(instr.gpr8); 346 std::string op_a = GetRegister(instr.gpr8);
289
290 std::string op_b = instr.ffma.negate_b ? "-" : ""; 347 std::string op_b = instr.ffma.negate_b ? "-" : "";
291 op_b += GetUniform(instr.uniform);
292
293 std::string op_c = instr.ffma.negate_c ? "-" : ""; 348 std::string op_c = instr.ffma.negate_c ? "-" : "";
294 op_c += GetRegister(instr.gpr39);
295 349
296 switch (instr.opcode.EffectiveOpCode()) { 350 switch (instr.opcode.EffectiveOpCode()) {
297 case OpCode::Id::FFMA_CR: { 351 case OpCode::Id::FFMA_CR: {
298 SetDest(0, dest, op_a + " * " + op_b + " + " + op_c, 1, 1); 352 op_b += GetUniform(instr.uniform);
353 op_c += GetRegister(instr.gpr39);
299 break; 354 break;
300 } 355 }
301 356 case OpCode::Id::FFMA_RR: {
302 default: { 357 op_b += GetRegister(instr.gpr20);
303 LOG_CRITICAL(HW_GPU, "Unhandled arithmetic FFMA instruction: 0x%02x (%s): 0x%08x", 358 op_c += GetRegister(instr.gpr39);
304 static_cast<unsigned>(instr.opcode.EffectiveOpCode()), 359 break;
305 OpCode::GetInfo(instr.opcode).name.c_str(), instr.hex); 360 }
306 throw DecompileFail("Unhandled instruction"); 361 case OpCode::Id::FFMA_RC: {
362 op_b += GetRegister(instr.gpr39);
363 op_c += GetUniform(instr.uniform);
307 break; 364 break;
308 } 365 }
366 case OpCode::Id::FFMA_IMM: {
367 op_b += GetImmediate(instr);
368 op_c += GetRegister(instr.gpr39);
369 break;
309 } 370 }
371 default: {
372 NGLOG_CRITICAL(HW_GPU, "Unhandled FFMA instruction: {} ({}): {}",
373 static_cast<unsigned>(instr.opcode.EffectiveOpCode()),
374 OpCode::GetInfo(instr.opcode).name, instr.hex);
375 UNREACHABLE();
376 }
377 }
378
379 SetDest(0, dest, op_a + " * " + op_b + " + " + op_c, 1, 1);
310 break; 380 break;
311 } 381 }
312 case OpCode::Type::Memory: { 382 case OpCode::Type::Memory: {
@@ -315,22 +385,33 @@ private:
315 385
316 switch (instr.opcode.EffectiveOpCode()) { 386 switch (instr.opcode.EffectiveOpCode()) {
317 case OpCode::Id::LD_A: { 387 case OpCode::Id::LD_A: {
318 ASSERT(instr.attribute.fmt20.size == 0); 388 ASSERT_MSG(instr.attribute.fmt20.size == 0, "untested");
319 SetDest(instr.attribute.fmt20.element, gpr0, GetInputAttribute(attribute), 1, 4); 389 SetDest(instr.attribute.fmt20.element, gpr0, GetInputAttribute(attribute), 1, 4);
320 break; 390 break;
321 } 391 }
322 case OpCode::Id::ST_A: { 392 case OpCode::Id::ST_A: {
323 ASSERT(instr.attribute.fmt20.size == 0); 393 ASSERT_MSG(instr.attribute.fmt20.size == 0, "untested");
324 SetDest(instr.attribute.fmt20.element, GetOutputAttribute(attribute), gpr0, 4, 1); 394 SetDest(instr.attribute.fmt20.element, GetOutputAttribute(attribute), gpr0, 4, 1);
325 break; 395 break;
326 } 396 }
327 default: { 397 case OpCode::Id::TEXS: {
328 LOG_CRITICAL(HW_GPU, "Unhandled memory instruction: 0x%02x (%s): 0x%08x", 398 ASSERT_MSG(instr.attribute.fmt20.size == 4, "untested");
329 static_cast<unsigned>(instr.opcode.EffectiveOpCode()), 399 const std::string op_a = GetRegister(instr.gpr8);
330 OpCode::GetInfo(instr.opcode).name.c_str(), instr.hex); 400 const std::string op_b = GetRegister(instr.gpr20);
331 throw DecompileFail("Unhandled instruction"); 401 const std::string sampler = GetSampler(instr.sampler);
402 const std::string coord = "vec2(" + op_a + ", " + op_b + ")";
403 const std::string texture = "texture(" + sampler + ", " + coord + ")";
404 for (unsigned elem = 0; elem < instr.attribute.fmt20.size; ++elem) {
405 SetDest(elem, GetRegister(instr.gpr0, elem), texture, 1, 4);
406 }
332 break; 407 break;
333 } 408 }
409 default: {
410 NGLOG_CRITICAL(HW_GPU, "Unhandled memory instruction: {} ({}): {}",
411 static_cast<unsigned>(instr.opcode.EffectiveOpCode()),
412 OpCode::GetInfo(instr.opcode).name, instr.hex);
413 UNREACHABLE();
414 }
334 } 415 }
335 break; 416 break;
336 } 417 }
@@ -342,14 +423,18 @@ private:
342 offset = PROGRAM_END - 1; 423 offset = PROGRAM_END - 1;
343 break; 424 break;
344 } 425 }
345 426 case OpCode::Id::IPA: {
346 default: { 427 const auto& attribute = instr.attribute.fmt28;
347 LOG_CRITICAL(HW_GPU, "Unhandled instruction: 0x%02x (%s): 0x%08x", 428 std::string dest = GetRegister(instr.gpr0);
348 static_cast<unsigned>(instr.opcode.EffectiveOpCode()), 429 SetDest(attribute.element, dest, GetInputAttribute(attribute.index), 1, 4);
349 OpCode::GetInfo(instr.opcode).name.c_str(), instr.hex);
350 throw DecompileFail("Unhandled instruction");
351 break; 430 break;
352 } 431 }
432 default: {
433 NGLOG_CRITICAL(HW_GPU, "Unhandled instruction: {} ({}): {}",
434 static_cast<unsigned>(instr.opcode.EffectiveOpCode()),
435 OpCode::GetInfo(instr.opcode).name, instr.hex);
436 UNREACHABLE();
437 }
353 } 438 }
354 439
355 break; 440 break;
@@ -514,7 +599,7 @@ boost::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code,
514 GLSLGenerator generator(subroutines, program_code, main_offset, stage); 599 GLSLGenerator generator(subroutines, program_code, main_offset, stage);
515 return ProgramResult{generator.GetShaderCode(), generator.GetEntries()}; 600 return ProgramResult{generator.GetShaderCode(), generator.GetEntries()};
516 } catch (const DecompileFail& exception) { 601 } catch (const DecompileFail& exception) {
517 LOG_ERROR(HW_GPU, "Shader decompilation failed: %s", exception.what()); 602 NGLOG_ERROR(HW_GPU, "Shader decompilation failed: {}", exception.what());
518 } 603 }
519 return boost::none; 604 return boost::none;
520} 605}
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp
index aeea1c805..8b7f17601 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp
@@ -27,10 +27,13 @@ out gl_PerVertex {
27 vec4 gl_Position; 27 vec4 gl_Position;
28}; 28};
29 29
30out vec4 position;
31
30void main() { 32void main() {
31 exec_shader(); 33 exec_shader();
32}
33 34
35 gl_Position = position;
36}
34)"; 37)";
35 out += program.first; 38 out += program.first;
36 return {out, program.second}; 39 return {out, program.second};
@@ -46,6 +49,7 @@ ProgramResult GenerateFragmentShader(const ShaderSetup& setup, const MaxwellFSCo
46 .get_value_or({}); 49 .get_value_or({});
47 out += R"( 50 out += R"(
48 51
52in vec4 position;
49out vec4 color; 53out vec4 color;
50 54
51uniform sampler2D tex[32]; 55uniform sampler2D tex[32];
diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h
index aa5026cce..a49265b38 100644
--- a/src/video_core/renderer_opengl/maxwell_to_gl.h
+++ b/src/video_core/renderer_opengl/maxwell_to_gl.h
@@ -102,4 +102,68 @@ inline GLenum WrapMode(Tegra::Texture::WrapMode wrap_mode) {
102 return {}; 102 return {};
103} 103}
104 104
105inline GLenum BlendEquation(Maxwell::Blend::Equation equation) {
106 switch (equation) {
107 case Maxwell::Blend::Equation::Add:
108 return GL_FUNC_ADD;
109 case Maxwell::Blend::Equation::Subtract:
110 return GL_FUNC_SUBTRACT;
111 case Maxwell::Blend::Equation::ReverseSubtract:
112 return GL_FUNC_REVERSE_SUBTRACT;
113 case Maxwell::Blend::Equation::Min:
114 return GL_MIN;
115 case Maxwell::Blend::Equation::Max:
116 return GL_MAX;
117 }
118 NGLOG_CRITICAL(Render_OpenGL, "Unimplemented blend equation={}", static_cast<u32>(equation));
119 UNREACHABLE();
120 return {};
121}
122
123inline GLenum BlendFunc(Maxwell::Blend::Factor factor) {
124 switch (factor) {
125 case Maxwell::Blend::Factor::Zero:
126 return GL_ZERO;
127 case Maxwell::Blend::Factor::One:
128 return GL_ONE;
129 case Maxwell::Blend::Factor::SourceColor:
130 return GL_SRC_COLOR;
131 case Maxwell::Blend::Factor::OneMinusSourceColor:
132 return GL_ONE_MINUS_SRC_COLOR;
133 case Maxwell::Blend::Factor::SourceAlpha:
134 return GL_SRC_ALPHA;
135 case Maxwell::Blend::Factor::OneMinusSourceAlpha:
136 return GL_ONE_MINUS_SRC_ALPHA;
137 case Maxwell::Blend::Factor::DestAlpha:
138 return GL_DST_ALPHA;
139 case Maxwell::Blend::Factor::OneMinusDestAlpha:
140 return GL_ONE_MINUS_DST_ALPHA;
141 case Maxwell::Blend::Factor::DestColor:
142 return GL_DST_COLOR;
143 case Maxwell::Blend::Factor::OneMinusDestColor:
144 return GL_ONE_MINUS_DST_COLOR;
145 case Maxwell::Blend::Factor::SourceAlphaSaturate:
146 return GL_SRC_ALPHA_SATURATE;
147 case Maxwell::Blend::Factor::Source1Color:
148 return GL_SRC1_COLOR;
149 case Maxwell::Blend::Factor::OneMinusSource1Color:
150 return GL_ONE_MINUS_SRC1_COLOR;
151 case Maxwell::Blend::Factor::Source1Alpha:
152 return GL_SRC1_ALPHA;
153 case Maxwell::Blend::Factor::OneMinusSource1Alpha:
154 return GL_ONE_MINUS_SRC1_ALPHA;
155 case Maxwell::Blend::Factor::ConstantColor:
156 return GL_CONSTANT_COLOR;
157 case Maxwell::Blend::Factor::OneMinusConstantColor:
158 return GL_ONE_MINUS_CONSTANT_COLOR;
159 case Maxwell::Blend::Factor::ConstantAlpha:
160 return GL_CONSTANT_ALPHA;
161 case Maxwell::Blend::Factor::OneMinusConstantAlpha:
162 return GL_ONE_MINUS_CONSTANT_ALPHA;
163 }
164 NGLOG_CRITICAL(Render_OpenGL, "Unimplemented blend factor={}", static_cast<u32>(factor));
165 UNREACHABLE();
166 return {};
167}
168
105} // namespace MaxwellToGL 169} // namespace MaxwellToGL