GLES: Implement logic ops via fb fetch (#608)

* GLES: Implement logic ops via fb fetch

* Attempt to fix deprecated libglx-mesa0 package

* Update Qt_Build.yml

* GLES: Enable fb fetch instead of requiring it

* GLES: Add support for GL_ARM_shader_framebuffer_fetch

* Fix GL_EXT_shader_framebuffer_fetch behavior
This commit is contained in:
wheremyfoodat 2024-10-13 21:17:24 +00:00 committed by GitHub
parent 5eb628eb5f
commit fa9ce5fc70
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 111 additions and 12 deletions

View file

@ -1,6 +1,10 @@
#include "PICA/pica_frag_config.hpp"
#include "PICA/regs.hpp"
#include "PICA/shader_gen.hpp"
// We can include the driver headers here since they shouldn't have any actual API-specific code
#include "renderer_gl/gl_driver.hpp"
using namespace PICA;
using namespace PICA::ShaderGen;
@ -96,7 +100,7 @@ std::string FragmentGenerator::getDefaultVertexShader() {
return ret;
}
std::string FragmentGenerator::generate(const FragmentConfig& config) {
std::string FragmentGenerator::generate(const FragmentConfig& config, void* driverInfo) {
std::string ret = "";
switch (api) {
@ -105,6 +109,27 @@ std::string FragmentGenerator::generate(const FragmentConfig& config) {
default: break;
}
// For GLES we need to enable & use the framebuffer fetch extension in order to emulate logic ops
bool emitLogicOps = api == API::GLES && config.outConfig.logicOpMode != PICA::LogicOpMode::Copy && driverInfo != nullptr;
if (emitLogicOps) {
auto driver = static_cast<OpenGL::Driver*>(driverInfo);
// If the driver does not support framebuffer fetch at all, don't emit logic op code
if (!driver->supportFbFetch()) {
emitLogicOps = false;
}
// Figure out which fb fetch extension we have and enable it
else {
if (driver->supportsExtFbFetch) {
ret += "\n#extension GL_EXT_shader_framebuffer_fetch : enable\n#define fb_color fragColor\n";
} else if (driver->supportsArmFbFetch) {
ret += "\n#extension GL_ARM_shader_framebuffer_fetch : enable\n#define fb_color gl_LastFragColorARM[0]\n";
}
}
}
bool unimplementedFlag = false;
if (api == API::GLES) {
ret += R"(
@ -194,10 +219,13 @@ std::string FragmentGenerator::generate(const FragmentConfig& config) {
}
compileFog(ret, config);
applyAlphaTest(ret, config);
ret += "fragColor = combinerOutput;\n}"; // End of main function
if (!emitLogicOps) {
ret += "fragColor = combinerOutput;\n}"; // End of main function
} else {
compileLogicOps(ret, config);
}
return ret;
}
@ -673,3 +701,28 @@ void FragmentGenerator::compileFog(std::string& shader, const PICA::FragmentConf
shader += "float fog_factor = clamp(value.r + value.g * delta, 0.0, 1.0);";
shader += "combinerOutput.rgb = mix(fog_color, combinerOutput.rgb, fog_factor);";
}
void FragmentGenerator::compileLogicOps(std::string& shader, const PICA::FragmentConfig& config) {
if (api != API::GLES) [[unlikely]] {
Helpers::warn("Shadergen: Unsupported API for compileLogicOps");
shader += "fragColor = combinerOutput;\n}"; // End of main function
return;
}
shader += "fragColor = ";
switch (config.outConfig.logicOpMode) {
case PICA::LogicOpMode::Copy: shader += "combinerOutput"; break;
case PICA::LogicOpMode::Nop: shader += "fb_color"; break;
case PICA::LogicOpMode::Clear: shader += "vec4(0.0)"; break;
case PICA::LogicOpMode::Set: shader += "vec4(uintBitsToFloat(0xFFFFFFFFu))"; break;
case PICA::LogicOpMode::InvertedCopy: shader += "vec4(uvec4(combinerOutput * 255.0) ^ uvec4(0xFFu)) * (1.0 / 255.0)"; break;
default:
shader += "combinerOutput";
Helpers::warn("Shadergen: Unimplemented logic op mode");
break;
}
shader += ";\n}"; // End of main function
}

View file

@ -167,6 +167,10 @@ void RendererGL::initGraphicsContextInternal() {
reset();
// Populate our driver info structure
driverInfo.supportsExtFbFetch = GLAD_GL_EXT_shader_framebuffer_fetch != 0;
driverInfo.supportsArmFbFetch = GLAD_GL_ARM_shader_framebuffer_fetch != 0;
// Initialize the default vertex shader used with shadergen
std::string defaultShadergenVSSource = fragShaderGen.getDefaultVertexShader();
defaultShadergenVs.create({defaultShadergenVSSource.c_str(), defaultShadergenVSSource.size()}, OpenGL::Vertex);
@ -839,12 +843,16 @@ OpenGL::Program& RendererGL::getSpecializedShader() {
constexpr uint uboBlockBinding = 2;
PICA::FragmentConfig fsConfig(regs);
// If we're not on GLES, ignore the logic op configuration and don't generate redundant shaders for it, since we use hw logic ops
#ifndef USING_GLES
fsConfig.outConfig.logicOpMode = PICA::LogicOpMode(0);
#endif
CachedProgram& programEntry = shaderCache[fsConfig];
OpenGL::Program& program = programEntry.program;
if (!program.exists()) {
std::string fs = fragShaderGen.generate(fsConfig);
std::string fs = fragShaderGen.generate(fsConfig, &driverInfo);
OpenGL::Shader fragShader({fs.c_str(), fs.size()}, OpenGL::Fragment);
program.create({defaultShadergenVs, fragShader});