Skip to content

Commit

Permalink
GLES: Implement logic ops via fb fetch (#608)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
wheremyfoodat authored Oct 13, 2024
1 parent 5eb628e commit fa9ce5f
Show file tree
Hide file tree
Showing 12 changed files with 111 additions and 12 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/Hydra_Build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ jobs:

- name: Install misc packages
run: |
sudo apt-get update && sudo apt install libx11-dev libgl1-mesa-glx mesa-common-dev libfuse2 libwayland-dev
sudo apt-get update && sudo apt install libx11-dev libgl1 libglx-mesa0 mesa-common-dev libfuse2 libwayland-dev
- name: Install newer Clang
run: |
Expand Down Expand Up @@ -160,7 +160,7 @@ jobs:

- name: Install misc packages
run: |
sudo apt-get update && sudo apt install libx11-dev libgl1-mesa-glx mesa-common-dev libfuse2 libwayland-dev
sudo apt-get update && sudo apt install libx11-dev libgl1 libglx-mesa0 mesa-common-dev libfuse2 libwayland-dev
- name: Setup Vulkan SDK
uses: humbletim/[email protected]
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/Linux_AppImage_Build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
run: git submodule update --init --recursive

- name: Install misc packages
run: sudo apt-get update && sudo apt install libx11-dev libgl1-mesa-glx mesa-common-dev libfuse2
run: sudo apt-get update && sudo apt install libx11-dev libgl1 libglx-mesa0 mesa-common-dev libfuse2

- name: Install newer Clang
run: |
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/Linux_Build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
run: git submodule update --init --recursive

- name: Install misc packages
run: sudo apt-get update && sudo apt install libx11-dev libgl1-mesa-glx mesa-common-dev
run: sudo apt-get update && sudo apt install libx11-dev libgl1 libglx-mesa0 mesa-common-dev

- name: Install newer Clang
run: |
Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/Qt_Build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,7 @@ jobs:

- name: Install misc packages
run: |
sudo apt-get update && sudo apt install libx11-dev libgl1-mesa-glx mesa-common-dev libfuse2 libwayland-dev libgl1-mesa-dev
sudo add-apt-repository -y ppa:savoury1/qt-6-2
sudo apt-get update && sudo apt install libx11-dev libgl1 libglx-mesa0 mesa-common-dev libfuse2 libwayland-dev libgl1-mesa-dev
sudo apt update
sudo apt install qt6-base-dev qt6-base-private-dev
Expand Down
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ if(ENABLE_OPENGL)
set(RENDERER_GL_INCLUDE_FILES third_party/opengl/opengl.hpp
include/renderer_gl/renderer_gl.hpp include/renderer_gl/textures.hpp
include/renderer_gl/surfaces.hpp include/renderer_gl/surface_cache.hpp
include/renderer_gl/gl_state.hpp
include/renderer_gl/gl_state.hpp include/renderer_gl/gl_driver.hpp
)

set(RENDERER_GL_SOURCE_FILES src/core/renderer_gl/renderer_gl.cpp
Expand Down
5 changes: 5 additions & 0 deletions include/PICA/pica_frag_config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ namespace PICA {
// enable == off means a CompareFunction of Always
BitField<0, 3, CompareFunction> alphaTestFunction;
BitField<3, 1, u32> depthMapEnable;
BitField<4, 4, LogicOpMode> logicOpMode;
};
};

Expand Down Expand Up @@ -214,6 +215,10 @@ namespace PICA {
(alphaTestConfig & 1) ? static_cast<PICA::CompareFunction>(alphaTestFunction) : PICA::CompareFunction::Always;
outConfig.depthMapEnable = regs[InternalRegs::DepthmapEnable] & 1;

// Shows if blending is enabled. If it is not enabled, then logic ops are enabled instead
const bool blendingEnabled = (regs[InternalRegs::ColourOperation] & (1 << 8)) != 0;
outConfig.logicOpMode = blendingEnabled ? LogicOpMode::Copy : LogicOpMode(Helpers::getBits<0, 4>(regs[InternalRegs::LogicOp]));

texConfig.texUnitConfig = regs[InternalRegs::TexUnitCfg];
texConfig.texEnvUpdateBuffer = regs[InternalRegs::TexEnvUpdateBuffer];

Expand Down
19 changes: 19 additions & 0 deletions include/PICA/regs.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,25 @@ namespace PICA {
GreaterOrEqual = 7,
};

enum class LogicOpMode : u32 {
Clear = 0,
And = 1,
ReverseAnd = 2,
Copy = 3,
Set = 4,
InvertedCopy = 5,
Nop = 6,
Invert = 7,
Nand = 8,
Or = 9,
Nor = 10,
Xor = 11,
Equiv = 12,
InvertedAnd = 13,
ReverseOr = 14,
InvertedOr = 15,
};

enum class FogMode : u32 {
Disabled = 0,
Fog = 5,
Expand Down
3 changes: 2 additions & 1 deletion include/PICA/shader_gen.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,11 @@ namespace PICA::ShaderGen {
bool isSamplerEnabled(u32 environmentID, u32 lutID);

void compileFog(std::string& shader, const PICA::FragmentConfig& config);
void compileLogicOps(std::string& shader, const PICA::FragmentConfig& config);

public:
FragmentGenerator(API api, Language language) : api(api), language(language) {}
std::string generate(const PICA::FragmentConfig& config);
std::string generate(const PICA::FragmentConfig& config, void* driverInfo = nullptr);
std::string getDefaultVertexShader();

void setTarget(API api, Language language) {
Expand Down
12 changes: 12 additions & 0 deletions include/renderer_gl/gl_driver.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#pragma once

// Information about our OpenGL/OpenGL ES driver that we should keep track of
// Stuff like whether specific extensions are supported, and potentially things like OpenGL context information
namespace OpenGL {
struct Driver {
bool supportsExtFbFetch = false;
bool supportsArmFbFetch = false;

bool supportFbFetch() const { return supportsExtFbFetch || supportsArmFbFetch; }
};
} // namespace OpenGL
2 changes: 2 additions & 0 deletions include/renderer_gl/renderer_gl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "PICA/pica_vertex.hpp"
#include "PICA/regs.hpp"
#include "PICA/shader_gen.hpp"
#include "gl_driver.hpp"
#include "gl_state.hpp"
#include "helpers.hpp"
#include "logger.hpp"
Expand Down Expand Up @@ -82,6 +83,7 @@ class RendererGL final : public Renderer {
OpenGL::Program& getSpecializedShader();

PICA::ShaderGen::FragmentGenerator fragShaderGen;
OpenGL::Driver driverInfo;

MAKE_LOG_FUNCTION(log, rendererLogger)
void setupBlending();
Expand Down
59 changes: 56 additions & 3 deletions src/core/PICA/shader_gen_glsl.cpp
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -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) {
Expand All @@ -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"(
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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
}
10 changes: 9 additions & 1 deletion src/core/renderer_gl/renderer_gl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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});
Expand Down

0 comments on commit fa9ce5f

Please sign in to comment.