Pica: Implement LogicOp function.
This commit is contained in:
parent
3b5ff61201
commit
e6ace38815
|
@ -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,12 +432,8 @@ 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;
|
||||||
|
|
|
@ -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 = {
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Reference in New Issue