citra-emu
/
citra-canary
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 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) { static unsigned NibblesPerPixel(TextureFormat format) {
switch (format) { switch (format) {
case TextureFormat::RGBA8: case TextureFormat::RGBA8:
@ -413,13 +432,9 @@ struct Regs {
} alpha_blending; } alpha_blending;
union { union {
enum Op { BitField<0, 4, LogicOp> logic_op;
Set = 4,
}; };
BitField<0, 4, Op> op;
} logic_op;
union { union {
BitField< 0, 8, u32> r; BitField< 0, 8, u32> r;
BitField< 8, 8, u32> g; 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 = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor, params.blend_equation_rgb);
blend_output.a() = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor, params.blend_equation_a).a(); blend_output.a() = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor, params.blend_equation_a).a();
} else { } else {
LOG_CRITICAL(HW_GPU, "logic op: %x", output_merger.logic_op); static auto LogicOp = [](u8 src, u8 dest, Regs::LogicOp op) -> u8 {
UNIMPLEMENTED(); 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 = { const Math::Vec4<u8> result = {

View File

@ -135,6 +135,7 @@ void RasterizerOpenGL::Reset() {
SyncBlendFuncs(); SyncBlendFuncs();
SyncBlendColor(); SyncBlendColor();
SyncAlphaTest(); SyncAlphaTest();
SyncLogicOp();
SyncStencilTest(); SyncStencilTest();
SyncDepthTest(); SyncDepthTest();
@ -249,6 +250,11 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
SyncDepthTest(); SyncDepthTest();
break; break;
// Logic op
case PICA_REG_INDEX(output_merger.logic_op):
SyncLogicOp();
break;
// TEV stage 0 // TEV stage 0
case PICA_REG_INDEX(tev_stage0.color_source1): case PICA_REG_INDEX(tev_stage0.color_source1):
SyncTevSources(0, regs.tev_stage0); SyncTevSources(0, regs.tev_stage0);
@ -633,6 +639,10 @@ void RasterizerOpenGL::SyncAlphaTest() {
glUniform1f(uniform_alphatest_ref, regs.output_merger.alpha_test.ref / 255.0f); 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() { void RasterizerOpenGL::SyncStencilTest() {
// TODO: Implement stencil test, mask, and op // TODO: Implement stencil test, mask, and op
} }

View File

@ -125,6 +125,9 @@ private:
/// Syncs the alpha test states to match the PICA register /// Syncs the alpha test states to match the PICA register
void SyncAlphaTest(); void SyncAlphaTest();
/// Syncs the logic op states to match the PICA register
void SyncLogicOp();
/// Syncs the stencil test states to match the PICA register /// Syncs the stencil test states to match the PICA register
void SyncStencilTest(); void SyncStencilTest();

View File

@ -32,6 +32,8 @@ OpenGLState::OpenGLState() {
blend.color.blue = 0.0f; blend.color.blue = 0.0f;
blend.color.alpha = 0.0f; blend.color.alpha = 0.0f;
logic_op = GL_COPY;
for (auto& texture_unit : texture_units) { for (auto& texture_unit : texture_units) {
texture_unit.enabled_2d = false; texture_unit.enabled_2d = false;
texture_unit.texture_2d = 0; texture_unit.texture_2d = 0;
@ -99,8 +101,13 @@ void OpenGLState::Apply() {
if (blend.enabled != cur_state.blend.enabled) { if (blend.enabled != cur_state.blend.enabled) {
if (blend.enabled) { if (blend.enabled) {
glEnable(GL_BLEND); glEnable(GL_BLEND);
cur_state.logic_op = GL_COPY;
glLogicOp(cur_state.logic_op);
glDisable(GL_COLOR_LOGIC_OP);
} else { } else {
glDisable(GL_BLEND); 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); 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 // Textures
for (unsigned texture_index = 0; texture_index < ARRAY_SIZE(texture_units); ++texture_index) { 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) { 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 } color; // GL_BLEND_COLOR
} blend; } blend;
GLenum logic_op; // GL_LOGIC_OP_MODE
// 3 texture units - one for each that is used in PICA fragment shader emulation // 3 texture units - one for each that is used in PICA fragment shader emulation
struct { struct {
bool enabled_2d; // GL_TEXTURE_2D 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]; 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) { inline GLenum CompareFunc(Pica::Regs::CompareFunc func) {
static const GLenum compare_func_table[] = { static const GLenum compare_func_table[] = {
GL_NEVER, // CompareFunc::Never GL_NEVER, // CompareFunc::Never