mirror of
https://github.com/yuzu-emu/yuzu.git
synced 2024-07-04 23:31:19 +01:00
Pica: Implement LogicOp function.
This commit is contained in:
parent
3b5ff61201
commit
e6ace38815
7 changed files with 135 additions and 8 deletions
|
@ -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,13 +432,9 @@ struct Regs {
|
|||
} alpha_blending;
|
||||
|
||||
union {
|
||||
enum Op {
|
||||
Set = 4,
|
||||
BitField<0, 4, LogicOp> logic_op;
|
||||
};
|
||||
|
||||
BitField<0, 4, Op> op;
|
||||
} logic_op;
|
||||
|
||||
union {
|
||||
BitField< 0, 8, u32> r;
|
||||
BitField< 8, 8, u32> g;
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue