mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-07 22:55:40 +12:00
GLSL shader gen: Add alpha test (...half of it I guess)
This commit is contained in:
parent
798c651a17
commit
842943fa4c
7 changed files with 108 additions and 38 deletions
|
@ -242,7 +242,7 @@ set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/termcolor.hpp
|
||||||
include/PICA/dynapica/shader_rec_emitter_arm64.hpp include/scheduler.hpp include/applets/error_applet.hpp include/PICA/shader_gen.hpp
|
include/PICA/dynapica/shader_rec_emitter_arm64.hpp include/scheduler.hpp include/applets/error_applet.hpp include/PICA/shader_gen.hpp
|
||||||
include/audio/dsp_core.hpp include/audio/null_core.hpp include/audio/teakra_core.hpp
|
include/audio/dsp_core.hpp include/audio/null_core.hpp include/audio/teakra_core.hpp
|
||||||
include/audio/miniaudio_device.hpp include/ring_buffer.hpp include/bitfield.hpp include/audio/dsp_shared_mem.hpp
|
include/audio/miniaudio_device.hpp include/ring_buffer.hpp include/bitfield.hpp include/audio/dsp_shared_mem.hpp
|
||||||
include/audio/hle_core.hpp include/capstone.hpp include/audio/aac.hpp
|
include/audio/hle_core.hpp include/capstone.hpp include/audio/aac.hpp include/PICA/pica_frag_config.hpp
|
||||||
)
|
)
|
||||||
|
|
||||||
cmrc_add_resource_library(
|
cmrc_add_resource_library(
|
||||||
|
|
53
include/PICA/pica_frag_config.hpp
Normal file
53
include/PICA/pica_frag_config.hpp
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
#pragma once
|
||||||
|
#include <array>
|
||||||
|
#include <cstring>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include "PICA/pica_hash.hpp"
|
||||||
|
#include "PICA/regs.hpp"
|
||||||
|
#include "bitfield.hpp"
|
||||||
|
#include "helpers.hpp"
|
||||||
|
|
||||||
|
namespace PICA {
|
||||||
|
struct OutputConfig {
|
||||||
|
union {
|
||||||
|
u32 raw;
|
||||||
|
// Merge the enable + compare function into 1 field to avoid duplicate shaders
|
||||||
|
// enable == off means a CompareFunction of Always
|
||||||
|
BitField<0, 3, CompareFunction> alphaTestFunction;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TextureConfig {
|
||||||
|
u32 texUnitConfig;
|
||||||
|
u32 texEnvUpdateBuffer;
|
||||||
|
|
||||||
|
// TODO: This should probably be a uniform
|
||||||
|
u32 texEnvBufferColor;
|
||||||
|
|
||||||
|
// There's 6 TEV stages, and each one is configured via 5 word-sized registers
|
||||||
|
std::array<u32, 5 * 6> tevConfigs;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FragmentConfig {
|
||||||
|
OutputConfig outConfig;
|
||||||
|
TextureConfig texConfig;
|
||||||
|
|
||||||
|
bool operator==(const FragmentConfig& config) const {
|
||||||
|
// Hash function and equality operator required by std::unordered_map
|
||||||
|
return std::memcmp(this, &config, sizeof(FragmentConfig)) == 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(
|
||||||
|
std::has_unique_object_representations<OutputConfig>() && std::has_unique_object_representations<TextureConfig>() &&
|
||||||
|
std::has_unique_object_representations<FragmentConfig>()
|
||||||
|
);
|
||||||
|
} // namespace PICA
|
||||||
|
|
||||||
|
// Override std::hash for our fragment config class
|
||||||
|
template <>
|
||||||
|
struct std::hash<PICA::FragmentConfig> {
|
||||||
|
std::size_t operator()(const PICA::FragmentConfig& config) const noexcept { return PICAHash::computeHash((const char*)&config, sizeof(config)); }
|
||||||
|
};
|
|
@ -345,6 +345,17 @@ namespace PICA {
|
||||||
GeometryPrimitive = 3,
|
GeometryPrimitive = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class CompareFunction : u32 {
|
||||||
|
Never = 0,
|
||||||
|
Always = 1,
|
||||||
|
Equal = 2,
|
||||||
|
NotEqual = 3,
|
||||||
|
Less = 4,
|
||||||
|
LessOrEqual = 5,
|
||||||
|
Greater = 6,
|
||||||
|
GreaterOrEqual = 7,
|
||||||
|
};
|
||||||
|
|
||||||
struct TexEnvConfig {
|
struct TexEnvConfig {
|
||||||
enum class Source : u8 {
|
enum class Source : u8 {
|
||||||
PrimaryColor = 0x0,
|
PrimaryColor = 0x0,
|
||||||
|
|
|
@ -24,6 +24,8 @@ namespace PICA::ShaderGen {
|
||||||
void getColorOperation(std::string& shader, PICA::TexEnvConfig::Operation op);
|
void getColorOperation(std::string& shader, PICA::TexEnvConfig::Operation op);
|
||||||
void getAlphaOperation(std::string& shader, PICA::TexEnvConfig::Operation op);
|
void getAlphaOperation(std::string& shader, PICA::TexEnvConfig::Operation op);
|
||||||
|
|
||||||
|
void applyAlphaTest(std::string& shader, const PICARegs& regs);
|
||||||
|
|
||||||
u32 textureConfig = 0;
|
u32 textureConfig = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "PICA/float_types.hpp"
|
#include "PICA/float_types.hpp"
|
||||||
|
#include "PICA/pica_frag_config.hpp"
|
||||||
#include "PICA/pica_hash.hpp"
|
#include "PICA/pica_hash.hpp"
|
||||||
#include "PICA/pica_vertex.hpp"
|
#include "PICA/pica_vertex.hpp"
|
||||||
#include "PICA/regs.hpp"
|
#include "PICA/regs.hpp"
|
||||||
|
@ -21,32 +22,6 @@
|
||||||
// More circular dependencies!
|
// More circular dependencies!
|
||||||
class GPU;
|
class GPU;
|
||||||
|
|
||||||
namespace PICA {
|
|
||||||
struct FragmentConfig {
|
|
||||||
u32 texUnitConfig;
|
|
||||||
u32 texEnvUpdateBuffer;
|
|
||||||
|
|
||||||
// TODO: This should probably be a uniform
|
|
||||||
u32 texEnvBufferColor;
|
|
||||||
|
|
||||||
// There's 6 TEV stages, and each one is configured via 5 word-sized registers
|
|
||||||
std::array<u32, 5 * 6> tevConfigs;
|
|
||||||
|
|
||||||
// Hash function and equality operator required by std::unordered_map
|
|
||||||
bool operator==(const FragmentConfig& config) const {
|
|
||||||
return std::memcmp(this, &config, sizeof(FragmentConfig)) == 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // namespace PICA
|
|
||||||
|
|
||||||
// Override std::hash for our fragment config class
|
|
||||||
template <>
|
|
||||||
struct std::hash<PICA::FragmentConfig> {
|
|
||||||
std::size_t operator()(const PICA::FragmentConfig& config) const noexcept {
|
|
||||||
return PICAHash::computeHash((const char*)&config, sizeof(config));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class RendererGL final : public Renderer {
|
class RendererGL final : public Renderer {
|
||||||
GLStateManager gl = {};
|
GLStateManager gl = {};
|
||||||
|
|
||||||
|
|
|
@ -144,6 +144,8 @@ std::string FragmentGenerator::generate(const PICARegs& regs) {
|
||||||
compileTEV(ret, i, regs);
|
compileTEV(ret, i, regs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applyAlphaTest(ret, regs);
|
||||||
|
|
||||||
ret += "fragColor = combinerOutput;\n";
|
ret += "fragColor = combinerOutput;\n";
|
||||||
ret += "}"; // End of main function
|
ret += "}"; // End of main function
|
||||||
ret += "\n\n\n\n\n\n\n\n\n\n\n\n\n";
|
ret += "\n\n\n\n\n\n\n\n\n\n\n\n\n";
|
||||||
|
@ -353,3 +355,25 @@ void FragmentGenerator::getAlphaOperation(std::string& shader, TexEnvConfig::Ope
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FragmentGenerator::applyAlphaTest(std::string& shader, const PICARegs& regs) {
|
||||||
|
const u32 alphaConfig = regs[InternalRegs::AlphaTestConfig];
|
||||||
|
// Alpha test disabled
|
||||||
|
if (Helpers::getBit<0>(alphaConfig) == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto function = static_cast<CompareFunction>(Helpers::getBits<4, 3>(alphaConfig));
|
||||||
|
|
||||||
|
shader += "if (";
|
||||||
|
switch (function) {
|
||||||
|
case CompareFunction::Never: shader += "true"; break;
|
||||||
|
case CompareFunction::Always: shader += "false"; break;
|
||||||
|
default:
|
||||||
|
Helpers::warn("Unimplemented alpha test function");
|
||||||
|
shader += "false";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
shader += ") { discard; }\n";
|
||||||
|
}
|
||||||
|
|
|
@ -796,22 +796,27 @@ std::optional<ColourBuffer> RendererGL::getColourBuffer(u32 addr, PICA::ColorFmt
|
||||||
|
|
||||||
OpenGL::Program& RendererGL::getSpecializedShader() {
|
OpenGL::Program& RendererGL::getSpecializedShader() {
|
||||||
PICA::FragmentConfig fsConfig;
|
PICA::FragmentConfig fsConfig;
|
||||||
fsConfig.texUnitConfig = regs[InternalRegs::TexUnitCfg];
|
auto& outConfig = fsConfig.outConfig;
|
||||||
fsConfig.texEnvUpdateBuffer = regs[InternalRegs::TexEnvUpdateBuffer];
|
auto& texConfig = fsConfig.texConfig;
|
||||||
fsConfig.texEnvBufferColor = regs[InternalRegs::TexEnvBufferColor];
|
|
||||||
|
auto alphaTestConfig = regs[InternalRegs::AlphaTestConfig];
|
||||||
|
auto alphaTestFunction = Helpers::getBits<4, 3>(alphaTestConfig);
|
||||||
|
outConfig.alphaTestFunction = (alphaTestConfig & 1) ? static_cast<PICA::CompareFunction>(alphaTestFunction) : PICA::CompareFunction::Always;
|
||||||
|
|
||||||
|
texConfig.texUnitConfig = regs[InternalRegs::TexUnitCfg];
|
||||||
|
texConfig.texEnvUpdateBuffer = regs[InternalRegs::TexEnvUpdateBuffer];
|
||||||
|
texConfig.texEnvBufferColor = 0;
|
||||||
|
|
||||||
// Set up TEV stages
|
// Set up TEV stages
|
||||||
std::memcpy(&fsConfig.tevConfigs[0 * 5], ®s[InternalRegs::TexEnv0Source], 5 * sizeof(u32));
|
std::memcpy(&texConfig.tevConfigs[0 * 5], ®s[InternalRegs::TexEnv0Source], 5 * sizeof(u32));
|
||||||
std::memcpy(&fsConfig.tevConfigs[1 * 5], ®s[InternalRegs::TexEnv1Source], 5 * sizeof(u32));
|
std::memcpy(&texConfig.tevConfigs[1 * 5], ®s[InternalRegs::TexEnv1Source], 5 * sizeof(u32));
|
||||||
std::memcpy(&fsConfig.tevConfigs[2 * 5], ®s[InternalRegs::TexEnv2Source], 5 * sizeof(u32));
|
std::memcpy(&texConfig.tevConfigs[2 * 5], ®s[InternalRegs::TexEnv2Source], 5 * sizeof(u32));
|
||||||
std::memcpy(&fsConfig.tevConfigs[3 * 5], ®s[InternalRegs::TexEnv3Source], 5 * sizeof(u32));
|
std::memcpy(&texConfig.tevConfigs[3 * 5], ®s[InternalRegs::TexEnv3Source], 5 * sizeof(u32));
|
||||||
std::memcpy(&fsConfig.tevConfigs[4 * 5], ®s[InternalRegs::TexEnv4Source], 5 * sizeof(u32));
|
std::memcpy(&texConfig.tevConfigs[4 * 5], ®s[InternalRegs::TexEnv4Source], 5 * sizeof(u32));
|
||||||
std::memcpy(&fsConfig.tevConfigs[5 * 5], ®s[InternalRegs::TexEnv5Source], 5 * sizeof(u32));
|
std::memcpy(&texConfig.tevConfigs[5 * 5], ®s[InternalRegs::TexEnv5Source], 5 * sizeof(u32));
|
||||||
|
|
||||||
OpenGL::Program& program = shaderCache[fsConfig];
|
OpenGL::Program& program = shaderCache[fsConfig];
|
||||||
if (!program.exists()) {
|
if (!program.exists()) {
|
||||||
printf("Creating specialized shader\n");
|
|
||||||
|
|
||||||
std::string vs = fragShaderGen.getVertexShader(regs);
|
std::string vs = fragShaderGen.getVertexShader(regs);
|
||||||
std::string fs = fragShaderGen.generate(regs);
|
std::string fs = fragShaderGen.generate(regs);
|
||||||
std::cout << vs << "\n\n" << fs << "\n";
|
std::cout << vs << "\n\n" << fs << "\n";
|
||||||
|
|
Loading…
Add table
Reference in a new issue