summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/video_core/pica.h27
-rw-r--r--src/video_core/rasterizer.cpp59
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp10
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h3
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp11
-rw-r--r--src/video_core/renderer_opengl/gl_state.h2
-rw-r--r--src/video_core/renderer_opengl/pica_to_gl.h31
7 files changed, 135 insertions, 8 deletions
diff --git a/src/video_core/pica.h b/src/video_core/pica.h
index fbc95a4b6..f8313d20d 100644
--- a/src/video_core/pica.h
+++ b/src/video_core/pica.h
@@ -162,6 +162,25 @@ struct Regs {
ETC1A4 = 13, // compressed
};
+ enum class LogicOp : u32 {
+ Clear = 0,
+ And = 1,
+ AndReverse = 2,
+ Copy = 3,
+ Set = 4,
+ CopyInverted = 5,
+ NoOp = 6,
+ Invert = 7,
+ Nand = 8,
+ Or = 9,
+ Nor = 10,
+ Xor = 11,
+ Equiv = 12,
+ AndInverted = 13,
+ OrReverse = 14,
+ OrInverted = 15,
+ };
+
static unsigned NibblesPerPixel(TextureFormat format) {
switch (format) {
case TextureFormat::RGBA8:
@@ -413,12 +432,8 @@ struct Regs {
} alpha_blending;
union {
- enum Op {
- Set = 4,
- };
-
- BitField<0, 4, Op> op;
- } logic_op;
+ BitField<0, 4, LogicOp> logic_op;
+ };
union {
BitField< 0, 8, u32> r;
diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp
index 8f39e609b..2613e398f 100644
--- a/src/video_core/rasterizer.cpp
+++ b/src/video_core/rasterizer.cpp
@@ -873,8 +873,63 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
blend_output = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor, params.blend_equation_rgb);
blend_output.a() = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor, params.blend_equation_a).a();
} else {
- LOG_CRITICAL(HW_GPU, "logic op: %x", output_merger.logic_op);
- UNIMPLEMENTED();
+ static auto LogicOp = [](u8 src, u8 dest, Regs::LogicOp op) -> u8 {
+ switch (op) {
+ case Regs::LogicOp::Clear:
+ return 0;
+
+ case Regs::LogicOp::And:
+ return src & dest;
+
+ case Regs::LogicOp::AndReverse:
+ return src & ~dest;
+
+ case Regs::LogicOp::Copy:
+ return src;
+
+ case Regs::LogicOp::Set:
+ return 255;
+
+ case Regs::LogicOp::CopyInverted:
+ return ~src;
+
+ case Regs::LogicOp::NoOp:
+ return dest;
+
+ case Regs::LogicOp::Invert:
+ return ~dest;
+
+ case Regs::LogicOp::Nand:
+ return ~(src & dest);
+
+ case Regs::LogicOp::Or:
+ return src | dest;
+
+ case Regs::LogicOp::Nor:
+ return ~(src | dest);
+
+ case Regs::LogicOp::Xor:
+ return src ^ dest;
+
+ case Regs::LogicOp::Equiv:
+ return ~(src ^ dest);
+
+ case Regs::LogicOp::AndInverted:
+ return ~src & dest;
+
+ case Regs::LogicOp::OrReverse:
+ return src | ~dest;
+
+ case Regs::LogicOp::OrInverted:
+ return ~src | dest;
+ }
+ };
+
+ blend_output = Math::MakeVec(
+ LogicOp(combiner_output.r(), dest.r(), output_merger.logic_op),
+ LogicOp(combiner_output.g(), dest.g(), output_merger.logic_op),
+ LogicOp(combiner_output.b(), dest.b(), output_merger.logic_op),
+ LogicOp(combiner_output.a(), dest.a(), output_merger.logic_op));
}
const Math::Vec4<u8> result = {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index bacdb7172..b51f8efdf 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -135,6 +135,7 @@ void RasterizerOpenGL::Reset() {
SyncBlendFuncs();
SyncBlendColor();
SyncAlphaTest();
+ SyncLogicOp();
SyncStencilTest();
SyncDepthTest();
@@ -249,6 +250,11 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
SyncDepthTest();
break;
+ // Logic op
+ case PICA_REG_INDEX(output_merger.logic_op):
+ SyncLogicOp();
+ break;
+
// TEV stage 0
case PICA_REG_INDEX(tev_stage0.color_source1):
SyncTevSources(0, regs.tev_stage0);
@@ -633,6 +639,10 @@ void RasterizerOpenGL::SyncAlphaTest() {
glUniform1f(uniform_alphatest_ref, regs.output_merger.alpha_test.ref / 255.0f);
}
+void RasterizerOpenGL::SyncLogicOp() {
+ state.logic_op = PicaToGL::LogicOp(Pica::g_state.regs.output_merger.logic_op);
+}
+
void RasterizerOpenGL::SyncStencilTest() {
// TODO: Implement stencil test, mask, and op
}
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 9896f8d04..d7d422b1f 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -125,6 +125,9 @@ private:
/// Syncs the alpha test states to match the PICA register
void SyncAlphaTest();
+ /// Syncs the logic op states to match the PICA register
+ void SyncLogicOp();
+
/// Syncs the stencil test states to match the PICA register
void SyncStencilTest();
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index 0d7ba1983..9c5f38f94 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -32,6 +32,8 @@ OpenGLState::OpenGLState() {
blend.color.blue = 0.0f;
blend.color.alpha = 0.0f;
+ logic_op = GL_COPY;
+
for (auto& texture_unit : texture_units) {
texture_unit.enabled_2d = false;
texture_unit.texture_2d = 0;
@@ -99,8 +101,13 @@ void OpenGLState::Apply() {
if (blend.enabled != cur_state.blend.enabled) {
if (blend.enabled) {
glEnable(GL_BLEND);
+
+ cur_state.logic_op = GL_COPY;
+ glLogicOp(cur_state.logic_op);
+ glDisable(GL_COLOR_LOGIC_OP);
} else {
glDisable(GL_BLEND);
+ glEnable(GL_COLOR_LOGIC_OP);
}
}
@@ -118,6 +125,10 @@ void OpenGLState::Apply() {
glBlendFuncSeparate(blend.src_rgb_func, blend.dst_rgb_func, blend.src_a_func, blend.dst_a_func);
}
+ if (logic_op != cur_state.logic_op) {
+ glLogicOp(logic_op);
+ }
+
// Textures
for (unsigned texture_index = 0; texture_index < ARRAY_SIZE(texture_units); ++texture_index) {
if (texture_units[texture_index].enabled_2d != cur_state.texture_units[texture_index].enabled_2d) {
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index 63dba2761..6b97721d6 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -42,6 +42,8 @@ public:
} color; // GL_BLEND_COLOR
} blend;
+ GLenum logic_op; // GL_LOGIC_OP_MODE
+
// 3 texture units - one for each that is used in PICA fragment shader emulation
struct {
bool enabled_2d; // GL_TEXTURE_2D
diff --git a/src/video_core/renderer_opengl/pica_to_gl.h b/src/video_core/renderer_opengl/pica_to_gl.h
index f8763e71b..e566f9f7a 100644
--- a/src/video_core/renderer_opengl/pica_to_gl.h
+++ b/src/video_core/renderer_opengl/pica_to_gl.h
@@ -71,6 +71,37 @@ inline GLenum BlendFunc(Pica::Regs::BlendFactor factor) {
return blend_func_table[(unsigned)factor];
}
+inline GLenum LogicOp(Pica::Regs::LogicOp op) {
+ static const GLenum logic_op_table[] = {
+ GL_CLEAR, // Clear
+ GL_AND, // And
+ GL_AND_REVERSE, // AndReverse
+ GL_COPY, // Copy
+ GL_SET, // Set
+ GL_COPY_INVERTED, // CopyInverted
+ GL_NOOP, // NoOp
+ GL_INVERT, // Invert
+ GL_NAND, // Nand
+ GL_OR, // Or
+ GL_NOR, // Nor
+ GL_XOR, // Xor
+ GL_EQUIV, // Equiv
+ GL_AND_INVERTED, // AndInverted
+ GL_OR_REVERSE, // OrReverse
+ GL_OR_INVERTED, // OrInverted
+ };
+
+ // Range check table for input
+ if ((unsigned)op >= ARRAY_SIZE(logic_op_table)) {
+ LOG_CRITICAL(Render_OpenGL, "Unknown logic op %d", op);
+ UNREACHABLE();
+
+ return GL_COPY;
+ }
+
+ return logic_op_table[(unsigned)op];
+}
+
inline GLenum CompareFunc(Pica::Regs::CompareFunc func) {
static const GLenum compare_func_table[] = {
GL_NEVER, // CompareFunc::Never