mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-07 22:55:40 +12:00
GLES: Implement logic ops via fb fetch
This commit is contained in:
parent
96f684e51c
commit
511e05becf
8 changed files with 89 additions and 6 deletions
|
@ -381,7 +381,7 @@ if(ENABLE_OPENGL)
|
||||||
set(RENDERER_GL_INCLUDE_FILES third_party/opengl/opengl.hpp
|
set(RENDERER_GL_INCLUDE_FILES third_party/opengl/opengl.hpp
|
||||||
include/renderer_gl/renderer_gl.hpp include/renderer_gl/textures.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/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
|
set(RENDERER_GL_SOURCE_FILES src/core/renderer_gl/renderer_gl.cpp
|
||||||
|
|
|
@ -17,6 +17,7 @@ namespace PICA {
|
||||||
// enable == off means a CompareFunction of Always
|
// enable == off means a CompareFunction of Always
|
||||||
BitField<0, 3, CompareFunction> alphaTestFunction;
|
BitField<0, 3, CompareFunction> alphaTestFunction;
|
||||||
BitField<3, 1, u32> depthMapEnable;
|
BitField<3, 1, u32> depthMapEnable;
|
||||||
|
BitField<4, 4, LogicOpMode> logicOpMode;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -214,6 +215,10 @@ namespace PICA {
|
||||||
(alphaTestConfig & 1) ? static_cast<PICA::CompareFunction>(alphaTestFunction) : PICA::CompareFunction::Always;
|
(alphaTestConfig & 1) ? static_cast<PICA::CompareFunction>(alphaTestFunction) : PICA::CompareFunction::Always;
|
||||||
outConfig.depthMapEnable = regs[InternalRegs::DepthmapEnable] & 1;
|
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.texUnitConfig = regs[InternalRegs::TexUnitCfg];
|
||||||
texConfig.texEnvUpdateBuffer = regs[InternalRegs::TexEnvUpdateBuffer];
|
texConfig.texEnvUpdateBuffer = regs[InternalRegs::TexEnvUpdateBuffer];
|
||||||
|
|
||||||
|
|
|
@ -396,6 +396,25 @@ namespace PICA {
|
||||||
GreaterOrEqual = 7,
|
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 {
|
enum class FogMode : u32 {
|
||||||
Disabled = 0,
|
Disabled = 0,
|
||||||
Fog = 5,
|
Fog = 5,
|
||||||
|
|
|
@ -25,10 +25,11 @@ namespace PICA::ShaderGen {
|
||||||
bool isSamplerEnabled(u32 environmentID, u32 lutID);
|
bool isSamplerEnabled(u32 environmentID, u32 lutID);
|
||||||
|
|
||||||
void compileFog(std::string& shader, const PICA::FragmentConfig& config);
|
void compileFog(std::string& shader, const PICA::FragmentConfig& config);
|
||||||
|
void compileLogicOps(std::string& shader, const PICA::FragmentConfig& config);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FragmentGenerator(API api, Language language) : api(api), language(language) {}
|
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();
|
std::string getDefaultVertexShader();
|
||||||
|
|
||||||
void setTarget(API api, Language language) {
|
void setTarget(API api, Language language) {
|
||||||
|
|
9
include/renderer_gl/gl_driver.hpp
Normal file
9
include/renderer_gl/gl_driver.hpp
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#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 supportsFbFetch = false;
|
||||||
|
};
|
||||||
|
} // namespace OpenGL
|
|
@ -12,6 +12,7 @@
|
||||||
#include "PICA/pica_vertex.hpp"
|
#include "PICA/pica_vertex.hpp"
|
||||||
#include "PICA/regs.hpp"
|
#include "PICA/regs.hpp"
|
||||||
#include "PICA/shader_gen.hpp"
|
#include "PICA/shader_gen.hpp"
|
||||||
|
#include "gl_driver.hpp"
|
||||||
#include "gl_state.hpp"
|
#include "gl_state.hpp"
|
||||||
#include "helpers.hpp"
|
#include "helpers.hpp"
|
||||||
#include "logger.hpp"
|
#include "logger.hpp"
|
||||||
|
@ -82,6 +83,7 @@ class RendererGL final : public Renderer {
|
||||||
OpenGL::Program& getSpecializedShader();
|
OpenGL::Program& getSpecializedShader();
|
||||||
|
|
||||||
PICA::ShaderGen::FragmentGenerator fragShaderGen;
|
PICA::ShaderGen::FragmentGenerator fragShaderGen;
|
||||||
|
OpenGL::Driver driverInfo;
|
||||||
|
|
||||||
MAKE_LOG_FUNCTION(log, rendererLogger)
|
MAKE_LOG_FUNCTION(log, rendererLogger)
|
||||||
void setupBlending();
|
void setupBlending();
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
#include "PICA/pica_frag_config.hpp"
|
#include "PICA/pica_frag_config.hpp"
|
||||||
#include "PICA/regs.hpp"
|
#include "PICA/regs.hpp"
|
||||||
#include "PICA/shader_gen.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;
|
||||||
using namespace PICA::ShaderGen;
|
using namespace PICA::ShaderGen;
|
||||||
|
|
||||||
|
@ -94,7 +98,7 @@ std::string FragmentGenerator::getDefaultVertexShader() {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string FragmentGenerator::generate(const FragmentConfig& config) {
|
std::string FragmentGenerator::generate(const FragmentConfig& config, void* driverInfo) {
|
||||||
std::string ret = "";
|
std::string ret = "";
|
||||||
|
|
||||||
switch (api) {
|
switch (api) {
|
||||||
|
@ -103,6 +107,14 @@ std::string FragmentGenerator::generate(const FragmentConfig& config) {
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For GLES we need to enable & use the framebuffer fetch extension in order to emulate logic ops
|
||||||
|
const bool emitLogicOps = api == API::GLES && config.outConfig.logicOpMode != PICA::LogicOpMode::Copy && driverInfo != nullptr &&
|
||||||
|
static_cast<OpenGL::Driver*>(driverInfo)->supportsFbFetch;
|
||||||
|
|
||||||
|
if (emitLogicOps) {
|
||||||
|
ret += "\n#extension GL_EXT_shader_framebuffer_fetch : require\n";
|
||||||
|
}
|
||||||
|
|
||||||
bool unimplementedFlag = false;
|
bool unimplementedFlag = false;
|
||||||
if (api == API::GLES) {
|
if (api == API::GLES) {
|
||||||
ret += R"(
|
ret += R"(
|
||||||
|
@ -192,10 +204,13 @@ std::string FragmentGenerator::generate(const FragmentConfig& config) {
|
||||||
}
|
}
|
||||||
|
|
||||||
compileFog(ret, config);
|
compileFog(ret, config);
|
||||||
|
|
||||||
applyAlphaTest(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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -671,3 +686,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 += "float fog_factor = clamp(value.r + value.g * delta, 0.0, 1.0);";
|
||||||
shader += "combinerOutput.rgb = mix(fog_color, combinerOutput.rgb, fog_factor);";
|
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 += "gl_LastFragData[0]"; 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
|
||||||
|
}
|
|
@ -167,6 +167,9 @@ void RendererGL::initGraphicsContextInternal() {
|
||||||
|
|
||||||
reset();
|
reset();
|
||||||
|
|
||||||
|
// Populate our driver info structure
|
||||||
|
driverInfo.supportsFbFetch = GLAD_GL_EXT_shader_framebuffer_fetch != 0;
|
||||||
|
|
||||||
// Initialize the default vertex shader used with shadergen
|
// Initialize the default vertex shader used with shadergen
|
||||||
std::string defaultShadergenVSSource = fragShaderGen.getDefaultVertexShader();
|
std::string defaultShadergenVSSource = fragShaderGen.getDefaultVertexShader();
|
||||||
defaultShadergenVs.create({defaultShadergenVSSource.c_str(), defaultShadergenVSSource.size()}, OpenGL::Vertex);
|
defaultShadergenVs.create({defaultShadergenVSSource.c_str(), defaultShadergenVSSource.size()}, OpenGL::Vertex);
|
||||||
|
@ -839,12 +842,16 @@ OpenGL::Program& RendererGL::getSpecializedShader() {
|
||||||
constexpr uint uboBlockBinding = 2;
|
constexpr uint uboBlockBinding = 2;
|
||||||
|
|
||||||
PICA::FragmentConfig fsConfig(regs);
|
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];
|
CachedProgram& programEntry = shaderCache[fsConfig];
|
||||||
OpenGL::Program& program = programEntry.program;
|
OpenGL::Program& program = programEntry.program;
|
||||||
|
|
||||||
if (!program.exists()) {
|
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);
|
OpenGL::Shader fragShader({fs.c_str(), fs.size()}, OpenGL::Fragment);
|
||||||
program.create({defaultShadergenVs, fragShader});
|
program.create({defaultShadergenVs, fragShader});
|
||||||
|
|
Loading…
Add table
Reference in a new issue