android: renderer_opengl: Partially implement glLogicOp on GLES.

This commit is contained in:
bunnei 2019-09-08 02:00:49 -04:00 committed by SachinVin
parent 853acce6c5
commit a941547c1c
4 changed files with 78 additions and 6 deletions

View file

@ -948,6 +948,10 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
// Blending // Blending
case PICA_REG_INDEX(framebuffer.output_merger.alphablend_enable): case PICA_REG_INDEX(framebuffer.output_merger.alphablend_enable):
if (GLES) {
// With GLES, we need this in the fragment shader to emulate logic operations
shader_dirty = true;
}
SyncBlendEnabled(); SyncBlendEnabled();
break; break;
case PICA_REG_INDEX(framebuffer.output_merger.alpha_blending): case PICA_REG_INDEX(framebuffer.output_merger.alpha_blending):
@ -1068,6 +1072,10 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
// Logic op // Logic op
case PICA_REG_INDEX(framebuffer.output_merger.logic_op): case PICA_REG_INDEX(framebuffer.output_merger.logic_op):
if (GLES) {
// With GLES, we need this in the fragment shader to emulate logic operations
shader_dirty = true;
}
SyncLogicOp(); SyncLogicOp();
break; break;
@ -1822,11 +1830,31 @@ void RasterizerOpenGL::SyncAlphaTest() {
} }
void RasterizerOpenGL::SyncLogicOp() { void RasterizerOpenGL::SyncLogicOp() {
state.logic_op = PicaToGL::LogicOp(Pica::g_state.regs.framebuffer.output_merger.logic_op); const auto& regs = Pica::g_state.regs;
state.logic_op = PicaToGL::LogicOp(regs.framebuffer.output_merger.logic_op);
if (GLES) {
if (!regs.framebuffer.output_merger.alphablend_enable) {
if (regs.framebuffer.output_merger.logic_op == Pica::FramebufferRegs::LogicOp::NoOp) {
// Color output is disabled by logic operation. We use color write mask to skip
// color but allow depth write.
state.color_mask = {};
}
}
}
} }
void RasterizerOpenGL::SyncColorWriteMask() { void RasterizerOpenGL::SyncColorWriteMask() {
const auto& regs = Pica::g_state.regs; const auto& regs = Pica::g_state.regs;
if (GLES) {
if (!regs.framebuffer.output_merger.alphablend_enable) {
if (regs.framebuffer.output_merger.logic_op == Pica::FramebufferRegs::LogicOp::NoOp) {
// Color output is disabled by logic operation. We use color write mask to skip
// color but allow depth write. Return early to avoid overwriting this.
return;
}
}
}
auto IsColorWriteEnabled = [&](u32 value) { auto IsColorWriteEnabled = [&](u32 value) {
return (regs.framebuffer.framebuffer.allow_color_write != 0 && value != 0) ? GL_TRUE return (regs.framebuffer.framebuffer.allow_color_write != 0 && value != 0) ? GL_TRUE

View file

@ -127,6 +127,17 @@ PicaFSConfig PicaFSConfig::BuildFromRegs(const Pica::Regs& regs) {
state.texture2_use_coord1 = regs.texturing.main_config.texture2_use_coord1 != 0; state.texture2_use_coord1 = regs.texturing.main_config.texture2_use_coord1 != 0;
if (GLES) {
// With GLES, we need this in the fragment shader to emulate logic operations
state.alphablend_enable =
Pica::g_state.regs.framebuffer.output_merger.alphablend_enable == 1;
state.logic_op = regs.framebuffer.output_merger.logic_op;
} else {
// We don't need these otherwise, reset them to avoid unnecessary shader generation
state.alphablend_enable = {};
state.logic_op = {};
}
// Copy relevant tev stages fields. // Copy relevant tev stages fields.
// We don't sync const_color here because of the high variance, it is a // We don't sync const_color here because of the high variance, it is a
// shader uniform instead. // shader uniform instead.
@ -1568,6 +1579,32 @@ do {
out += "color = byteround(last_tex_env_out);\n"; out += "color = byteround(last_tex_env_out);\n";
} }
if (GLES) {
if (!state.alphablend_enable) {
switch (state.logic_op) {
case FramebufferRegs::LogicOp::Clear:
out += "color = vec4(0);\n";
break;
case FramebufferRegs::LogicOp::Set:
out += "color = vec4(1);\n";
break;
case FramebufferRegs::LogicOp::Copy:
// Take the color output as-is
break;
case FramebufferRegs::LogicOp::CopyInverted:
out += "color = ~color;\n";
break;
case FramebufferRegs::LogicOp::NoOp:
// We need to discard the color, but not necessarily the depth. This is not possible
// with fragment shader alone, so we emulate this behavior on GLES with glColorMask.
break;
default:
LOG_CRITICAL(HW_GPU, "Unhandled logic_op {:x}", static_cast<int>(state.logic_op));
UNIMPLEMENTED();
}
}
}
out += '}'; out += '}';
return {std::move(out)}; return {std::move(out)};

View file

@ -61,6 +61,8 @@ struct PicaFSConfigState {
Pica::RasterizerRegs::DepthBuffering depthmap_enable; Pica::RasterizerRegs::DepthBuffering depthmap_enable;
Pica::TexturingRegs::FogMode fog_mode; Pica::TexturingRegs::FogMode fog_mode;
bool fog_flip; bool fog_flip;
bool alphablend_enable;
Pica::FramebufferRegs::LogicOp logic_op;
struct { struct {
struct { struct {

View file

@ -170,12 +170,19 @@ void OpenGLState::Apply() const {
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);
glDisable(GL_COLOR_LOGIC_OP);
} else { } else {
glDisable(GL_BLEND); glDisable(GL_BLEND);
}
// GLES does not support glLogicOp
if (!GLES) {
if (blend.enabled) {
glDisable(GL_COLOR_LOGIC_OP);
} else {
glEnable(GL_COLOR_LOGIC_OP); glEnable(GL_COLOR_LOGIC_OP);
} }
} }
}
if (blend.color.red != cur_state.blend.color.red || if (blend.color.red != cur_state.blend.color.red ||
blend.color.green != cur_state.blend.color.green || blend.color.green != cur_state.blend.color.green ||
@ -197,13 +204,11 @@ void OpenGLState::Apply() const {
glBlendEquationSeparate(blend.rgb_equation, blend.a_equation); glBlendEquationSeparate(blend.rgb_equation, blend.a_equation);
} }
// GLES3 does not support glLogicOp // GLES does not support glLogicOp
if (!GLES) { if (!GLES) {
if (logic_op != cur_state.logic_op) { if (logic_op != cur_state.logic_op) {
glLogicOp(logic_op); glLogicOp(logic_op);
} }
} else {
LOG_TRACE(Render_OpenGL, "glLogicOps are unimplemented...");
} }
// Textures // Textures