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:
static_assert(position < 8 * sizeof(T), "Invalid position");
static_assert(bits <= 8 * sizeof(T), "Invalid number of bits");
static_assert(bits > 0, "Invalid number of bits");
- static_assert(std::is_pod<T>::value, "Invalid base type");
+ static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable in a BitField");
};
#pragma pack()
-
-#if (__GNUC__ >= 5) || defined(__clang__) || defined(_MSC_VER)
-static_assert(std::is_trivially_copyable<BitField<0, 1, unsigned>>::value,
- "BitField must be trivially copyable");
-#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) {
regs.reg_array[method] = value;
-#define MAXWELL3D_REG_INDEX(field_name) (offsetof(Regs, field_name) / sizeof(u32))
-
switch (method) {
case MAXWELL3D_REG_INDEX(code_address.code_address_high):
case MAXWELL3D_REG_INDEX(code_address.code_address_low): {
@@ -136,7 +134,7 @@ void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) {
break;
}
-#undef MAXWELL3D_REG_INDEX
+ VideoCore::g_renderer->Rasterizer()->NotifyMaxwellRegisterChanged(method);
if (debug_context) {
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 @@
namespace Tegra {
namespace Engines {
+#define MAXWELL3D_REG_INDEX(field_name) \
+ (offsetof(Tegra::Engines::Maxwell3D::Regs, field_name) / sizeof(u32))
+
class Maxwell3D final {
public:
explicit Maxwell3D(MemoryManager& memory_manager);
@@ -254,6 +257,46 @@ public:
UnsignedInt = 0x2,
};
+ struct Blend {
+ enum class Equation : u32 {
+ Add = 1,
+ Subtract = 2,
+ ReverseSubtract = 3,
+ Min = 4,
+ Max = 5,
+ };
+
+ enum class Factor : u32 {
+ Zero = 0x1,
+ One = 0x2,
+ SourceColor = 0x3,
+ OneMinusSourceColor = 0x4,
+ SourceAlpha = 0x5,
+ OneMinusSourceAlpha = 0x6,
+ DestAlpha = 0x7,
+ OneMinusDestAlpha = 0x8,
+ DestColor = 0x9,
+ OneMinusDestColor = 0xa,
+ SourceAlphaSaturate = 0xb,
+ Source1Color = 0x10,
+ OneMinusSource1Color = 0x11,
+ Source1Alpha = 0x12,
+ OneMinusSource1Alpha = 0x13,
+ ConstantColor = 0x61,
+ OneMinusConstantColor = 0x62,
+ ConstantAlpha = 0x63,
+ OneMinusConstantAlpha = 0x64,
+ };
+
+ u32 separate_alpha;
+ Equation equation_rgb;
+ Factor factor_source_rgb;
+ Factor factor_dest_rgb;
+ Equation equation_a;
+ Factor factor_source_a;
+ Factor factor_dest_a;
+ };
+
union {
struct {
INSERT_PADDING_WORDS(0x200);
@@ -451,7 +494,9 @@ public:
}
} vertex_array[NumVertexArrays];
- INSERT_PADDING_WORDS(0x40);
+ Blend blend;
+
+ INSERT_PADDING_WORDS(0x39);
struct {
u32 limit_high;
@@ -616,6 +661,7 @@ ASSERT_REG_POSITION(draw, 0x585);
ASSERT_REG_POSITION(index_array, 0x5F2);
ASSERT_REG_POSITION(query, 0x6C0);
ASSERT_REG_POSITION(vertex_array[0], 0x700);
+ASSERT_REG_POSITION(blend, 0x780);
ASSERT_REG_POSITION(vertex_array_limit[0], 0x7C0);
ASSERT_REG_POSITION(shader_config[0], 0x800);
ASSERT_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 @@
#pragma once
+#include <cstring>
#include <map>
#include <string>
#include "common/bit_field.h"
@@ -12,14 +13,10 @@ namespace Tegra {
namespace Shader {
struct Register {
- Register() = default;
+ constexpr Register() = default;
constexpr Register(u64 value) : value(value) {}
- constexpr u64 GetIndex() const {
- return value;
- }
-
constexpr operator u64() const {
return value;
}
@@ -43,13 +40,13 @@ struct Register {
}
private:
- u64 value;
+ u64 value{};
};
union Attribute {
Attribute() = default;
- constexpr Attribute(u64 value) : value(value) {}
+ constexpr explicit Attribute(u64 value) : value(value) {}
enum class Index : u64 {
Position = 7,
@@ -68,7 +65,20 @@ union Attribute {
} fmt28;
BitField<39, 8, u64> reg;
- u64 value;
+ u64 value{};
+};
+
+union Sampler {
+ Sampler() = default;
+
+ constexpr explicit Sampler(u64 value) : value(value) {}
+
+ enum class Index : u64 {
+ Sampler_0 = 8,
+ };
+
+ BitField<36, 13, Index> index;
+ u64 value{};
};
union Uniform {
@@ -238,7 +248,7 @@ union OpCode {
BitField<55, 9, Id> op3;
BitField<52, 12, Id> op4;
BitField<51, 13, Id> op5;
- u64 value;
+ u64 value{};
};
static_assert(sizeof(OpCode) == 0x8, "Incorrect structure size");
@@ -280,6 +290,7 @@ enum class SubOp : u64 {
Lg2 = 0x3,
Rcp = 0x4,
Rsq = 0x5,
+ Min = 0x8,
};
union Instruction {
@@ -295,15 +306,25 @@ union Instruction {
BitField<20, 8, Register> gpr20;
BitField<20, 7, SubOp> sub_op;
BitField<28, 8, Register> gpr28;
- BitField<36, 13, u64> imm36;
BitField<39, 8, Register> gpr39;
union {
+ BitField<20, 19, u64> imm20;
BitField<45, 1, u64> negate_b;
BitField<46, 1, u64> abs_a;
BitField<48, 1, u64> negate_a;
BitField<49, 1, u64> abs_b;
BitField<50, 1, u64> abs_d;
+ BitField<56, 1, u64> negate_imm;
+
+ float GetImm20() const {
+ float result{};
+ u32 imm{static_cast<u32>(imm20)};
+ imm <<= 12;
+ imm |= negate_imm ? 0x80000000 : 0;
+ std::memcpy(&result, &imm, sizeof(imm));
+ return result;
+ }
} alu;
union {
@@ -311,11 +332,13 @@ union Instruction {
BitField<49, 1, u64> negate_c;
} ffma;
+ BitField<61, 1, u64> is_b_imm;
BitField<60, 1, u64> is_b_gpr;
BitField<59, 1, u64> is_c_gpr;
Attribute attribute;
Uniform uniform;
+ Sampler sampler;
u64 hex;
};
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:
virtual void DrawArrays() = 0;
/// Notify rasterizer that the specified Maxwell register has been changed
- virtual void NotifyMaxwellRegisterChanged(u32 id) = 0;
+ virtual void NotifyMaxwellRegisterChanged(u32 method) = 0;
/// Notify rasterizer that all caches should be flushed to Switch memory
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() {
}
}
-void RasterizerOpenGL::NotifyMaxwellRegisterChanged(u32 id) {}
+void RasterizerOpenGL::NotifyMaxwellRegisterChanged(u32 method) {
+ const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs;
+ switch (method) {
+ case MAXWELL3D_REG_INDEX(blend.separate_alpha):
+ ASSERT_MSG(false, "unimplemented");
+ break;
+ case MAXWELL3D_REG_INDEX(blend.equation_rgb):
+ state.blend.rgb_equation = MaxwellToGL::BlendEquation(regs.blend.equation_rgb);
+ break;
+ case MAXWELL3D_REG_INDEX(blend.factor_source_rgb):
+ state.blend.src_rgb_func = MaxwellToGL::BlendFunc(regs.blend.factor_source_rgb);
+ break;
+ case MAXWELL3D_REG_INDEX(blend.factor_dest_rgb):
+ state.blend.dst_rgb_func = MaxwellToGL::BlendFunc(regs.blend.factor_dest_rgb);
+ break;
+ case MAXWELL3D_REG_INDEX(blend.equation_a):
+ state.blend.a_equation = MaxwellToGL::BlendEquation(regs.blend.equation_a);
+ break;
+ case MAXWELL3D_REG_INDEX(blend.factor_source_a):
+ state.blend.src_a_func = MaxwellToGL::BlendFunc(regs.blend.factor_source_a);
+ break;
+ case MAXWELL3D_REG_INDEX(blend.factor_dest_a):
+ state.blend.dst_a_func = MaxwellToGL::BlendFunc(regs.blend.factor_dest_a);
+ break;
+ }
+}
void RasterizerOpenGL::FlushAll() {
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:
~RasterizerOpenGL() override;
void DrawArrays() override;
- void NotifyMaxwellRegisterChanged(u32 id) override;
+ void NotifyMaxwellRegisterChanged(u32 method) override;
void FlushAll() override;
void FlushRegion(VAddr addr, u64 size) override;
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;
using Tegra::Shader::Instruction;
using Tegra::Shader::OpCode;
using Tegra::Shader::Register;
+using Tegra::Shader::Sampler;
using Tegra::Shader::SubOp;
using Tegra::Shader::Uniform;
@@ -155,23 +156,27 @@ private:
/// Generates code representing an input attribute register.
std::string GetInputAttribute(Attribute::Index attribute) {
- declr_input_attribute.insert(attribute);
+ switch (attribute) {
+ case Attribute::Index::Position:
+ return "position";
+ default:
+ const u32 index{static_cast<u32>(attribute) -
+ static_cast<u32>(Attribute::Index::Attribute_0)};
+ if (attribute >= Attribute::Index::Attribute_0) {
+ declr_input_attribute.insert(attribute);
+ return "input_attribute_" + std::to_string(index);
+ }
- const u32 index{static_cast<u32>(attribute) -
- static_cast<u32>(Attribute::Index::Attribute_0)};
- if (attribute >= Attribute::Index::Attribute_0) {
- return "input_attribute_" + std::to_string(index);
+ NGLOG_CRITICAL(HW_GPU, "Unhandled input attribute: {}", index);
+ UNREACHABLE();
}
-
- LOG_CRITICAL(HW_GPU, "Unhandled input attribute: 0x%02x", index);
- UNREACHABLE();
}
/// Generates code representing an output attribute register.
std::string GetOutputAttribute(Attribute::Index attribute) {
switch (attribute) {
case Attribute::Index::Position:
- return "gl_Position";
+ return "position";
default:
const u32 index{static_cast<u32>(attribute) -
static_cast<u32>(Attribute::Index::Attribute_0)};
@@ -180,22 +185,42 @@ private:
return "output_attribute_" + std::to_string(index);
}
- LOG_CRITICAL(HW_GPU, "Unhandled output attribute: 0x%02x", index);
+ NGLOG_CRITICAL(HW_GPU, "Unhandled output attribute: {}", index);
UNREACHABLE();
}
}
+ /// Generates code representing an immediate value
+ static std::string GetImmediate(const Instruction& instr) {
+ return std::to_string(instr.alu.GetImm20());
+ }
+
/// Generates code representing a temporary (GPR) register.
- std::string GetRegister(const Register& reg) {
- return *declr_register.insert("register_" + std::to_string(reg)).first;
+ std::string GetRegister(const Register& reg, unsigned elem = 0) {
+ if (stage == Maxwell3D::Regs::ShaderStage::Fragment && reg < 4) {
+ // GPRs 0-3 are output color for the fragment shader
+ return std::string{"color."} + "rgba"[(reg + elem) & 3];
+ }
+
+ return *declr_register.insert("register_" + std::to_string(reg + elem)).first;
}
/// Generates code representing a uniform (C buffer) register.
std::string GetUniform(const Uniform& reg) {
- declr_const_buffers[reg.index].MarkAsUsed(reg.index, reg.offset, stage);
+ declr_const_buffers[reg.index].MarkAsUsed(static_cast<unsigned>(reg.index),
+ static_cast<unsigned>(reg.offset), stage);
return 'c' + std::to_string(reg.index) + '[' + std::to_string(reg.offset) + ']';
}
+ /// Generates code representing a texture sampler.
+ std::string GetSampler(const Sampler& sampler) const {
+ // TODO(Subv): Support more than just texture sampler 0
+ ASSERT_MSG(sampler.index == Sampler::Index::Sampler_0, "unsupported");
+ const unsigned index{static_cast<unsigned>(sampler.index.Value()) -
+ static_cast<unsigned>(Sampler::Index::Sampler_0)};
+ return "tex[" + std::to_string(index) + "]";
+ }
+
/**
* Adds code that calls a subroutine.
* @param subroutine the subroutine to call.
@@ -217,12 +242,13 @@ private:
* @param value the code representing the value to assign.
*/
void SetDest(u64 elem, const std::string& reg, const std::string& value,
- u64 dest_num_components, u64 value_num_components) {
+ u64 dest_num_components, u64 value_num_components, bool is_abs = false) {
std::string swizzle = ".";
swizzle += "xyzw"[elem];
std::string dest = reg + (dest_num_components != 1 ? swizzle : "");
std::string src = "(" + value + ")" + (value_num_components != 1 ? swizzle : "");
+ src = is_abs ? "abs(" + src + ")" : src;
shader.AddLine(dest + " = " + src + ";");
}
@@ -240,8 +266,6 @@ private:
switch (OpCode::GetInfo(instr.opcode).type) {
case OpCode::Type::Arithmetic: {
- ASSERT(!instr.alu.abs_d);
-
std::string dest = GetRegister(instr.gpr0);
std::string op_a = instr.alu.negate_a ? "-" : "";
op_a += GetRegister(instr.gpr8);
@@ -250,63 +274,109 @@ private:
}
std::string op_b = instr.alu.negate_b ? "-" : "";
- if (instr.is_b_gpr) {
- op_b += GetRegister(instr.gpr20);
+
+ if (instr.is_b_imm) {
+ op_b += GetImmediate(instr);
} else {
- op_b += GetUniform(instr.uniform);
+ if (instr.is_b_gpr) {
+ op_b += GetRegister(instr.gpr20);
+ } else {
+ op_b += GetUniform(instr.uniform);
+ }
}
+
if (instr.alu.abs_b) {
op_b = "abs(" + op_b + ")";
}
switch (instr.opcode.EffectiveOpCode()) {
case OpCode::Id::FMUL_C:
- case OpCode::Id::FMUL_R: {
- SetDest(0, dest, op_a + " * " + op_b, 1, 1);
+ case OpCode::Id::FMUL_R:
+ case OpCode::Id::FMUL_IMM: {
+ SetDest(0, dest, op_a + " * " + op_b, 1, 1, instr.alu.abs_d);
break;
}
case OpCode::Id::FADD_C:
- case OpCode::Id::FADD_R: {
- SetDest(0, dest, op_a + " + " + op_b, 1, 1);
+ case OpCode::Id::FADD_R:
+ case OpCode::Id::FADD_IMM: {
+ SetDest(0, dest, op_a + " + " + op_b, 1, 1, instr.alu.abs_d);
break;
}
- default: {
- LOG_CRITICAL(HW_GPU, "Unhandled arithmetic instruction: 0x%02x (%s): 0x%08x",
- static_cast<unsigned>(instr.opcode.EffectiveOpCode()),
- OpCode::GetInfo(instr.opcode).name.c_str(), instr.hex);
- throw DecompileFail("Unhandled instruction");
+ case OpCode::Id::MUFU: {
+ switch (instr.sub_op) {
+ case SubOp::Cos:
+ SetDest(0, dest, "cos(" + op_a + ")", 1, 1, instr.alu.abs_d);
+ break;
+ case SubOp::Sin:
+ SetDest(0, dest, "sin(" + op_a + ")", 1, 1, instr.alu.abs_d);
+ break;
+ case SubOp::Ex2:
+ SetDest(0, dest, "exp2(" + op_a + ")", 1, 1, instr.alu.abs_d);
+ break;
+ case SubOp::Lg2:
+ SetDest(0, dest, "log2(" + op_a + ")", 1, 1, instr.alu.abs_d);
+ break;
+ case SubOp::Rcp:
+ SetDest(0, dest, "1.0 / " + op_a, 1, 1, instr.alu.abs_d);
+ break;
+ case SubOp::Rsq:
+ SetDest(0, dest, "inversesqrt(" + op_a + ")", 1, 1, instr.alu.abs_d);
+ break;
+ case SubOp::Min:
+ SetDest(0, dest, "min(" + op_a + "," + op_b + ")", 1, 1, instr.alu.abs_d);
+ break;
+ default:
+ NGLOG_CRITICAL(HW_GPU, "Unhandled MUFU sub op: {}",
+ static_cast<unsigned>(instr.sub_op.Value()));
+ UNREACHABLE();
+ }
break;
}
+ default: {
+ NGLOG_CRITICAL(HW_GPU, "Unhandled arithmetic instruction: {} ({}): {}",
+ static_cast<unsigned>(instr.opcode.EffectiveOpCode()),
+ OpCode::GetInfo(instr.opcode).name, instr.hex);
+ UNREACHABLE();
+ }
}
break;
}
case OpCode::Type::Ffma: {
- ASSERT_MSG(!instr.ffma.negate_b, "untested");
- ASSERT_MSG(!instr.ffma.negate_c, "untested");
-
std::string dest = GetRegister(instr.gpr0);
std::string op_a = GetRegister(instr.gpr8);
-
std::string op_b = instr.ffma.negate_b ? "-" : "";
- op_b += GetUniform(instr.uniform);
-
std::string op_c = instr.ffma.negate_c ? "-" : "";
- op_c += GetRegister(instr.gpr39);
switch (instr.opcode.EffectiveOpCode()) {
case OpCode::Id::FFMA_CR: {
- SetDest(0, dest, op_a + " * " + op_b + " + " + op_c, 1, 1);
+ op_b += GetUniform(instr.uniform);
+ op_c += GetRegister(instr.gpr39);
break;
}
-
- default: {
- LOG_CRITICAL(HW_GPU, "Unhandled arithmetic FFMA instruction: 0x%02x (%s): 0x%08x",
- static_cast<unsigned>(instr.opcode.EffectiveOpCode()),
- OpCode::GetInfo(instr.opcode).name.c_str(), instr.hex);
- throw DecompileFail("Unhandled instruction");
+ case OpCode::Id::FFMA_RR: {
+ op_b += GetRegister(instr.gpr20);
+ op_c += GetRegister(instr.gpr39);
+ break;
+ }
+ case OpCode::Id::FFMA_RC: {
+ op_b += GetRegister(instr.gpr39);
+ op_c += GetUniform(instr.uniform);
break;
}
+ case OpCode::Id::FFMA_IMM: {
+ op_b += GetImmediate(instr);
+ op_c += GetRegister(instr.gpr39);
+ break;
}
+ default: {
+ NGLOG_CRITICAL(HW_GPU, "Unhandled FFMA instruction: {} ({}): {}",
+ static_cast<unsigned>(instr.opcode.EffectiveOpCode()),
+ OpCode::GetInfo(instr.opcode).name, instr.hex);
+ UNREACHABLE();
+ }
+ }
+
+ SetDest(0, dest, op_a + " * " + op_b + " + " + op_c, 1, 1);
break;
}
case OpCode::Type::Memory: {
@@ -315,22 +385,33 @@ private:
switch (instr.opcode.EffectiveOpCode()) {
case OpCode::Id::LD_A: {
- ASSERT(instr.attribute.fmt20.size == 0);
+ ASSERT_MSG(instr.attribute.fmt20.size == 0, "untested");
SetDest(instr.attribute.fmt20.element, gpr0, GetInputAttribute(attribute), 1, 4);
break;
}
case OpCode::Id::ST_A: {
- ASSERT(instr.attribute.fmt20.size == 0);
+ ASSERT_MSG(instr.attribute.fmt20.size == 0, "untested");
SetDest(instr.attribute.fmt20.element, GetOutputAttribute(attribute), gpr0, 4, 1);
break;
}
- default: {
- LOG_CRITICAL(HW_GPU, "Unhandled memory instruction: 0x%02x (%s): 0x%08x",
- static_cast<unsigned>(instr.opcode.EffectiveOpCode()),
- OpCode::GetInfo(instr.opcode).name.c_str(), instr.hex);
- throw DecompileFail("Unhandled instruction");
+ case OpCode::Id::TEXS: {
+ ASSERT_MSG(instr.attribute.fmt20.size == 4, "untested");
+ const std::string op_a = GetRegister(instr.gpr8);
+ const std::string op_b = GetRegister(instr.gpr20);
+ const std::string sampler = GetSampler(instr.sampler);
+ const std::string coord = "vec2(" + op_a + ", " + op_b + ")";
+ const std::string texture = "texture(" + sampler + ", " + coord + ")";
+ for (unsigned elem = 0; elem < instr.attribute.fmt20.size; ++elem) {
+ SetDest(elem, GetRegister(instr.gpr0, elem), texture, 1, 4);
+ }
break;
}
+ default: {
+ NGLOG_CRITICAL(HW_GPU, "Unhandled memory instruction: {} ({}): {}",
+ static_cast<unsigned>(instr.opcode.EffectiveOpCode()),
+ OpCode::GetInfo(instr.opcode).name, instr.hex);
+ UNREACHABLE();
+ }
}
break;
}
@@ -342,14 +423,18 @@ private:
offset = PROGRAM_END - 1;
break;
}
-
- default: {
- LOG_CRITICAL(HW_GPU, "Unhandled instruction: 0x%02x (%s): 0x%08x",
- static_cast<unsigned>(instr.opcode.EffectiveOpCode()),
- OpCode::GetInfo(instr.opcode).name.c_str(), instr.hex);
- throw DecompileFail("Unhandled instruction");
+ case OpCode::Id::IPA: {
+ const auto& attribute = instr.attribute.fmt28;
+ std::string dest = GetRegister(instr.gpr0);
+ SetDest(attribute.element, dest, GetInputAttribute(attribute.index), 1, 4);
break;
}
+ default: {
+ NGLOG_CRITICAL(HW_GPU, "Unhandled instruction: {} ({}): {}",
+ static_cast<unsigned>(instr.opcode.EffectiveOpCode()),
+ OpCode::GetInfo(instr.opcode).name, instr.hex);
+ UNREACHABLE();
+ }
}
break;
@@ -514,7 +599,7 @@ boost::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code,
GLSLGenerator generator(subroutines, program_code, main_offset, stage);
return ProgramResult{generator.GetShaderCode(), generator.GetEntries()};
} catch (const DecompileFail& exception) {
- LOG_ERROR(HW_GPU, "Shader decompilation failed: %s", exception.what());
+ NGLOG_ERROR(HW_GPU, "Shader decompilation failed: {}", exception.what());
}
return boost::none;
}
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 {
vec4 gl_Position;
};
+out vec4 position;
+
void main() {
exec_shader();
-}
+ gl_Position = position;
+}
)";
out += program.first;
return {out, program.second};
@@ -46,6 +49,7 @@ ProgramResult GenerateFragmentShader(const ShaderSetup& setup, const MaxwellFSCo
.get_value_or({});
out += R"(
+in vec4 position;
out vec4 color;
uniform 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) {
return {};
}
+inline GLenum BlendEquation(Maxwell::Blend::Equation equation) {
+ switch (equation) {
+ case Maxwell::Blend::Equation::Add:
+ return GL_FUNC_ADD;
+ case Maxwell::Blend::Equation::Subtract:
+ return GL_FUNC_SUBTRACT;
+ case Maxwell::Blend::Equation::ReverseSubtract:
+ return GL_FUNC_REVERSE_SUBTRACT;
+ case Maxwell::Blend::Equation::Min:
+ return GL_MIN;
+ case Maxwell::Blend::Equation::Max:
+ return GL_MAX;
+ }
+ NGLOG_CRITICAL(Render_OpenGL, "Unimplemented blend equation={}", static_cast<u32>(equation));
+ UNREACHABLE();
+ return {};
+}
+
+inline GLenum BlendFunc(Maxwell::Blend::Factor factor) {
+ switch (factor) {
+ case Maxwell::Blend::Factor::Zero:
+ return GL_ZERO;
+ case Maxwell::Blend::Factor::One:
+ return GL_ONE;
+ case Maxwell::Blend::Factor::SourceColor:
+ return GL_SRC_COLOR;
+ case Maxwell::Blend::Factor::OneMinusSourceColor:
+ return GL_ONE_MINUS_SRC_COLOR;
+ case Maxwell::Blend::Factor::SourceAlpha:
+ return GL_SRC_ALPHA;
+ case Maxwell::Blend::Factor::OneMinusSourceAlpha:
+ return GL_ONE_MINUS_SRC_ALPHA;
+ case Maxwell::Blend::Factor::DestAlpha:
+ return GL_DST_ALPHA;
+ case Maxwell::Blend::Factor::OneMinusDestAlpha:
+ return GL_ONE_MINUS_DST_ALPHA;
+ case Maxwell::Blend::Factor::DestColor:
+ return GL_DST_COLOR;
+ case Maxwell::Blend::Factor::OneMinusDestColor:
+ return GL_ONE_MINUS_DST_COLOR;
+ case Maxwell::Blend::Factor::SourceAlphaSaturate:
+ return GL_SRC_ALPHA_SATURATE;
+ case Maxwell::Blend::Factor::Source1Color:
+ return GL_SRC1_COLOR;
+ case Maxwell::Blend::Factor::OneMinusSource1Color:
+ return GL_ONE_MINUS_SRC1_COLOR;
+ case Maxwell::Blend::Factor::Source1Alpha:
+ return GL_SRC1_ALPHA;
+ case Maxwell::Blend::Factor::OneMinusSource1Alpha:
+ return GL_ONE_MINUS_SRC1_ALPHA;
+ case Maxwell::Blend::Factor::ConstantColor:
+ return GL_CONSTANT_COLOR;
+ case Maxwell::Blend::Factor::OneMinusConstantColor:
+ return GL_ONE_MINUS_CONSTANT_COLOR;
+ case Maxwell::Blend::Factor::ConstantAlpha:
+ return GL_CONSTANT_ALPHA;
+ case Maxwell::Blend::Factor::OneMinusConstantAlpha:
+ return GL_ONE_MINUS_CONSTANT_ALPHA;
+ }
+ NGLOG_CRITICAL(Render_OpenGL, "Unimplemented blend factor={}", static_cast<u32>(factor));
+ UNREACHABLE();
+ return {};
+}
+
} // namespace MaxwellToGL