citra-emu
/
citra
Archived
1
0
Fork 0

Pica: Implement LogicOp function.

This commit is contained in:
bunnei 2015-05-25 18:39:03 -04:00
parent 3b5ff61201
commit e6ace38815
7 changed files with 135 additions and 8 deletions

View File

@ -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;

View File

@ -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 = {

View File

@ -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
}

View File

@ -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();

View File

@ -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) {

View File

@ -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

View File

@ -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