summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/bit_field.h7
-rw-r--r--src/video_core/engines/shader_bytecode.h43
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp197
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.cpp6
4 files changed, 180 insertions, 73 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/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/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];