From 3d5a39e647fceb5bf17a288df32677773f4a9034 Mon Sep 17 00:00:00 2001 From: fzurita Date: Mon, 11 Oct 2021 19:22:23 -0400 Subject: [PATCH] Add a new "fast" shader path that doesn't use texelFetch in glsl --- projects/msvc/GLideN64.vcxproj | 12 + projects/msvc/GLideN64.vcxproj.filters | 36 + src/CMakeLists.txt | 6 + src/Config.cpp | 1 + src/Config.h | 1 + src/GLideNUI/ConfigDialog.cpp | 2 + src/GLideNUI/Settings.cpp | 11 +- src/GLideNUI/configDialog.ui | 10 + src/Graphics/CombinerProgram.cpp | 1 + .../GLSL/glsl_CombinerProgramBuilder.cpp | 2820 +---------------- .../GLSL/glsl_CombinerProgramBuilder.h | 183 +- .../glsl_CombinerProgramBuilderAccurate.cpp | 1238 ++++++++ .../glsl_CombinerProgramBuilderAccurate.h | 46 + .../glsl_CombinerProgramBuilderCommon.cpp | 1681 ++++++++++ .../GLSL/glsl_CombinerProgramBuilderCommon.h | 118 + .../GLSL/glsl_CombinerProgramBuilderFast.cpp | 1186 +++++++ .../GLSL/glsl_CombinerProgramBuilderFast.h | 47 + .../glsl_CombinerProgramUniformFactory.cpp | 1265 +------- .../GLSL/glsl_CombinerProgramUniformFactory.h | 89 +- ..._CombinerProgramUniformFactoryAccurate.cpp | 397 +++ ...sl_CombinerProgramUniformFactoryAccurate.h | 28 + ...sl_CombinerProgramUniformFactoryCommon.cpp | 914 ++++++ ...glsl_CombinerProgramUniformFactoryCommon.h | 161 + ...glsl_CombinerProgramUniformFactoryFast.cpp | 433 +++ .../glsl_CombinerProgramUniformFactoryFast.h | 26 + .../OpenGLContext/GLSL/glsl_ShaderStorage.cpp | 17 +- .../OpenGLContext/GLSL/glsl_ShaderStorage.h | 2 +- .../OpenGLContext/opengl_ContextImpl.cpp | 11 +- src/GraphicsDrawer.cpp | 67 +- src/Textures.cpp | 270 +- src/Textures.h | 8 +- src/gDP.cpp | 4 +- src/mupenplus/Config_mupenplus.cpp | 3 + 33 files changed, 6998 insertions(+), 4096 deletions(-) create mode 100644 src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilderAccurate.cpp create mode 100644 src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilderAccurate.h create mode 100644 src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilderCommon.cpp create mode 100644 src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilderCommon.h create mode 100644 src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilderFast.cpp create mode 100644 src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilderFast.h create mode 100644 src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactoryAccurate.cpp create mode 100644 src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactoryAccurate.h create mode 100644 src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactoryCommon.cpp create mode 100644 src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactoryCommon.h create mode 100644 src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactoryFast.cpp create mode 100644 src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactoryFast.h diff --git a/projects/msvc/GLideN64.vcxproj b/projects/msvc/GLideN64.vcxproj index 4c466f1b..56358ff6 100644 --- a/projects/msvc/GLideN64.vcxproj +++ b/projects/msvc/GLideN64.vcxproj @@ -309,8 +309,14 @@ copy /Y "$(OutDir)$(TargetName).*" "$(Mupen64PluginsDir_x64)") + + + + + + @@ -465,8 +471,14 @@ copy /Y "$(OutDir)$(TargetName).*" "$(Mupen64PluginsDir_x64)") + + + + + + diff --git a/projects/msvc/GLideN64.vcxproj.filters b/projects/msvc/GLideN64.vcxproj.filters index c514ca90..1687c729 100644 --- a/projects/msvc/GLideN64.vcxproj.filters +++ b/projects/msvc/GLideN64.vcxproj.filters @@ -221,6 +221,9 @@ Source Files\Graphics\OpenGL\GLSL + + Source Files\Graphics\OpenGL\GLSL + Source Files\Graphics\OpenGL\GLSL @@ -236,6 +239,9 @@ Source Files\Graphics\OpenGL\GLSL + + Source Files\Graphics\OpenGL\GLSL + Source Files\Graphics\OpenGL\GLSL @@ -425,6 +431,18 @@ Source Files\BufferCopy + + Source Files\Graphics\OpenGL\GLSL + + + Source Files\Graphics\OpenGL\GLSL + + + Source Files\Graphics\OpenGL\GLSL + + + Source Files\Graphics\OpenGL\GLSL + @@ -787,6 +805,24 @@ Resource Files + + Header Files\Graphics\OpenGL\GLSL + + + Header Files\Graphics\OpenGL\GLSL + + + Header Files\Graphics\OpenGL\GLSL + + + Header Files\Graphics\OpenGL\GLSL + + + Header Files\Graphics\OpenGL\GLSL + + + Header Files\Graphics\OpenGL\GLSL + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 63f0722e..e3e82dbb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -89,8 +89,14 @@ set(GLideN64_SOURCES Graphics/OpenGLContext/opengl_Utils.cpp Graphics/OpenGLContext/GLSL/glsl_CombinerInputs.cpp Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilder.cpp + Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilderCommon.cpp + Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilderAccurate.cpp + Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilderFast.cpp Graphics/OpenGLContext/GLSL/glsl_CombinerProgramImpl.cpp Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactory.cpp + Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactoryCommon.cpp + Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactoryAccurate.cpp + Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactoryFast.cpp Graphics/OpenGLContext/GLSL/glsl_FXAA.cpp Graphics/OpenGLContext/GLSL/glsl_ShaderStorage.cpp Graphics/OpenGLContext/GLSL/glsl_SpecialShadersFactory.cpp diff --git a/src/Config.cpp b/src/Config.cpp index bdc68473..772a60ec 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -51,6 +51,7 @@ void Config::resetToDefaults() generalEmulation.enableShadersStorage = 1; generalEmulation.enableLegacyBlending = 0; generalEmulation.enableHybridFilter = 1; + generalEmulation.enableInaccurateTextureCoordinates = 0; generalEmulation.hacks = 0; #if defined(OS_ANDROID) || defined(OS_IOS) generalEmulation.enableFragmentDepthWrite = 0; diff --git a/src/Config.h b/src/Config.h index e854b858..9f87076d 100644 --- a/src/Config.h +++ b/src/Config.h @@ -65,6 +65,7 @@ struct Config u32 enableShadersStorage; u32 enableLegacyBlending; u32 enableHybridFilter; + u32 enableInaccurateTextureCoordinates; u32 enableFragmentDepthWrite; u32 hacks; #if defined(OS_ANDROID) || defined(OS_IOS) diff --git a/src/GLideNUI/ConfigDialog.cpp b/src/GLideNUI/ConfigDialog.cpp index 5c2efa4c..b1c0e1ee 100644 --- a/src/GLideNUI/ConfigDialog.cpp +++ b/src/GLideNUI/ConfigDialog.cpp @@ -223,6 +223,7 @@ void ConfigDialog::_init(bool reInit, bool blockCustomSettings) // Emulation settings ui->emulateLodCheckBox->setChecked(config.generalEmulation.enableLOD != 0); + ui->enableInaccurateTextureCoordinatesCheckBox->setChecked(config.generalEmulation.enableInaccurateTextureCoordinates != 0); ui->enableHWLightingCheckBox->setChecked(config.generalEmulation.enableHWLighting != 0); ui->enableCoverageCheckBox->setChecked(config.generalEmulation.enableCoverage != 0); ui->enableShadersStorageCheckBox->setChecked(config.generalEmulation.enableShadersStorage != 0); @@ -562,6 +563,7 @@ void ConfigDialog::accept(bool justSave) { // Emulation settings config.generalEmulation.enableLOD = ui->emulateLodCheckBox->isChecked() ? 1 : 0; + config.generalEmulation.enableInaccurateTextureCoordinates = ui->enableInaccurateTextureCoordinatesCheckBox->isChecked() ? 1 : 0; config.generalEmulation.enableHWLighting = ui->enableHWLightingCheckBox->isChecked() ? 1 : 0; config.generalEmulation.enableCoverage = ui->enableCoverageCheckBox->isChecked() ? 1 : 0; config.generalEmulation.enableShadersStorage = ui->enableShadersStorageCheckBox->isChecked() ? 1 : 0; diff --git a/src/GLideNUI/Settings.cpp b/src/GLideNUI/Settings.cpp index cee4ef13..5685f575 100644 --- a/src/GLideNUI/Settings.cpp +++ b/src/GLideNUI/Settings.cpp @@ -48,6 +48,7 @@ void _loadSettings(QSettings & settings) config.generalEmulation.enableHiresNoiseDithering = settings.value("enableHiresNoiseDithering", config.generalEmulation.enableHiresNoiseDithering).toInt(); config.generalEmulation.rdramImageDitheringMode = settings.value("rdramImageDitheringMode", config.generalEmulation.rdramImageDitheringMode).toInt(); config.generalEmulation.enableLOD = settings.value("enableLOD", config.generalEmulation.enableLOD).toInt(); + config.generalEmulation.enableInaccurateTextureCoordinates = settings.value("enableFastInaccurateShaders", config.generalEmulation.enableInaccurateTextureCoordinates).toInt(); config.generalEmulation.enableHWLighting = settings.value("enableHWLighting", config.generalEmulation.enableHWLighting).toInt(); config.generalEmulation.enableCoverage = settings.value("enableCoverage", config.generalEmulation.enableCoverage).toInt(); config.generalEmulation.enableShadersStorage = settings.value("enableShadersStorage", config.generalEmulation.enableShadersStorage).toInt(); @@ -193,6 +194,7 @@ void _writeSettingsToFile(const QString & filename) settings.setValue("enableHiresNoiseDithering", config.generalEmulation.enableHiresNoiseDithering); settings.setValue("rdramImageDitheringMode", config.generalEmulation.rdramImageDitheringMode); settings.setValue("enableLOD", config.generalEmulation.enableLOD); + settings.setValue("enableFastInaccurateShaders", config.generalEmulation.enableInaccurateTextureCoordinates); settings.setValue("enableHWLighting", config.generalEmulation.enableHWLighting); settings.setValue("enableCoverage", config.generalEmulation.enableCoverage); settings.setValue("enableShadersStorage", config.generalEmulation.enableShadersStorage); @@ -359,8 +361,8 @@ void resetSettings(const QString & _strIniFolder) static u32 Adler32(u32 crc, const void *buffer, u32 count) { - register u32 s1 = crc & 0xFFFF; - register u32 s2 = (crc >> 16) & 0xFFFF; + u32 s1 = crc & 0xFFFF; + u32 s2 = (crc >> 16) & 0xFFFF; int k; const u8 *Buffer = (const u8*)buffer; @@ -465,6 +467,7 @@ void saveCustomRomSettings(const QString & _strIniFolder, const char * _strRomNa WriteCustomSetting(generalEmulation, enableHiresNoiseDithering); WriteCustomSetting(generalEmulation, rdramImageDitheringMode); WriteCustomSetting(generalEmulation, enableLOD); + WriteCustomSetting(generalEmulation, enableInaccurateTextureCoordinates); WriteCustomSetting(generalEmulation, enableHWLighting); WriteCustomSetting(generalEmulation, enableCoverage); WriteCustomSetting(generalEmulation, enableShadersStorage); @@ -540,11 +543,11 @@ void saveCustomRomSettings(const QString & _strIniFolder, const char * _strRomNa settings.beginGroup("hotkeys"); for (u32 idx = 0; idx < Config::HotKey::hkTotal; ++idx) { - if (origConfig.hotkeys.keys[idx] != config.hotkeys.keys[idx] || + if (origConfig.hotkeys.keys[idx] != config.hotkeys.keys[idx] || origConfig.hotkeys.keys[idx] != settings.value(Config::hotkeyIniName(idx), config.hotkeys.keys[idx]).toInt()) { settings.setValue(Config::hotkeyIniName(idx), config.hotkeys.keys[idx]); } - if (origConfig.hotkeys.enabledKeys[idx] != config.hotkeys.enabledKeys[idx] || + if (origConfig.hotkeys.enabledKeys[idx] != config.hotkeys.enabledKeys[idx] || origConfig.hotkeys.enabledKeys[idx] != settings.value(Config::enabledHotkeyIniName(idx), config.hotkeys.enabledKeys[idx]).toInt()) { settings.setValue(Config::enabledHotkeyIniName(idx), config.hotkeys.enabledKeys[idx]); } diff --git a/src/GLideNUI/configDialog.ui b/src/GLideNUI/configDialog.ui index b0b50476..4a8f4f1f 100644 --- a/src/GLideNUI/configDialog.ui +++ b/src/GLideNUI/configDialog.ui @@ -1098,6 +1098,16 @@ + + + + <html><head/><body><p><span style=" font-weight:600;">Enable inaccurate texture coordinates. </span></p><p>Enables inaccurate texture coordinate calculations. This can improve performance and texture pack compatibity at the cost of accuracy.</p><p>[Recommended: Unchecked, unless performance is hurt or for texture pack compatibility]</p></body></html> + + + Enable inaccurate texture coordinates + + + diff --git a/src/Graphics/CombinerProgram.cpp b/src/Graphics/CombinerProgram.cpp index bc3bcd86..be59bc71 100644 --- a/src/Graphics/CombinerProgram.cpp +++ b/src/Graphics/CombinerProgram.cpp @@ -21,6 +21,7 @@ namespace graphics { vecOptions.push_back(config.frameBufferEmulation.N64DepthCompare == Config::dcCompatible ? 1 : 0); vecOptions.push_back(config.generalEmulation.enableLegacyBlending); vecOptions.push_back(config.generalEmulation.enableFragmentDepthWrite); + vecOptions.push_back(config.generalEmulation.enableInaccurateTextureCoordinates); u32 optionsSet = 0; for (u32 i = 0; i < vecOptions.size(); ++i) optionsSet |= vecOptions[i] << i; diff --git a/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilder.cpp b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilder.cpp index 141f5451..f0552f9f 100644 --- a/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilder.cpp +++ b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilder.cpp @@ -3,44 +3,16 @@ #include #include #include "glsl_Utils.h" -#include "glsl_ShaderPart.h" #include "glsl_CombinerInputs.h" #include "glsl_CombinerProgramImpl.h" -#include "glsl_CombinerProgramBuilder.h" -#include "glsl_CombinerProgramUniformFactory.h" +#include "glsl_CombinerProgramBuilderAccurate.h" +#include "glsl_CombinerProgramUniformFactoryAccurate.h" #include "GraphicsDrawer.h" -using namespace glsl; +namespace glsl { -class TextureConvert { -public: - void setMode(u32 _mode) { - m_mode = _mode; - } - - bool getBilerp1() const { - return (m_mode & 1) != 0; - } - - bool getBilerp0() const { - return (m_mode & 2) != 0; - } - - bool useYUVCoversion() const { - return (m_mode & 3) != 3; - } - - bool useTextureFiltering() const { - return (m_mode & 3) != 0; - } - -private: - u32 m_mode; -}; - - -u32 g_cycleType = G_CYC_1CYCLE; -TextureConvert g_textureConvert; +u32 CombinerProgramBuilder::s_cycleType = G_CYC_1CYCLE; +TextureConvert CombinerProgramBuilder::s_textureConvert; /*---------------_compileCombiner-------------*/ @@ -230,2546 +202,28 @@ CombinerInputs _compileCombiner(const CombinerStage & _stage, const char** _Inpu return inputs; } -/*---------------ShaderParts-------------*/ - -class VertexShaderHeader : public ShaderPart -{ -public: - VertexShaderHeader(const opengl::GLInfo & _glinfo) - { - if (_glinfo.isGLES2) { - m_part = "#version 100 \n"; - m_part += - "#if (__VERSION__ > 120) \n" - "# define IN in \n" - "# define OUT out \n" - "#else \n" - "# define IN attribute \n" - "# define OUT varying \n" - "#ifndef GL_FRAGMENT_PRECISION_HIGH \n" - "# define highp mediump \n" - "#endif \n" - "#endif // __VERSION \n" - ; - } - else if (_glinfo.isGLESX) { - std::stringstream ss; - ss << "#version " << Utils::to_string(_glinfo.majorVersion) << Utils::to_string(_glinfo.minorVersion) << "0 es " << std::endl; - ss << "# define IN in" << std::endl << "# define OUT out" << std::endl; - if (_glinfo.noPerspective) { - ss << "#extension GL_NV_shader_noperspective_interpolation : enable" << std::endl - << "noperspective OUT highp float vZCoord;" << std::endl - << "uniform lowp int uClampMode;" << std::endl; - } - m_part = ss.str(); - } - else { - std::stringstream ss; - ss << "#version " << Utils::to_string(_glinfo.majorVersion) << Utils::to_string(_glinfo.minorVersion) << "0 core " << std::endl; - ss << "# define IN in" << std::endl << "# define OUT out" << std::endl; - m_part = ss.str(); - } - m_part += "uniform lowp vec2 uVertexOffset; \n"; - std::stringstream ss; - ss << "const lowp float screenSizeDims = " << std::setprecision(1) << std::fixed << SCREEN_SIZE_DIM << ";" << std::endl; - m_part += ss.str(); - } -}; - -class VertexShaderTexturedTriangle : public ShaderPart -{ -public: - VertexShaderTexturedTriangle(const opengl::GLInfo & _glinfo) - { - m_part = - "IN highp vec4 aPosition; \n" - "IN lowp vec4 aColor; \n" - "IN highp vec2 aTexCoord; \n" - "IN lowp float aNumLights; \n" - "IN highp vec4 aModify; \n" - "IN highp vec2 aBaryCoords; \n" - " \n" - "uniform int uTexturePersp; \n" - "uniform lowp int uTextureFilterMode; \n" - " \n" - "uniform lowp int uFogUsage; \n" - "uniform mediump vec2 uFogScale; \n" - "uniform mediump vec2 uScreenCoordsScale; \n" - " \n" - "uniform mediump vec2 uTexScale; \n" - "uniform mediump vec2 uVTrans; \n" - "uniform mediump vec2 uVScale; \n" - "uniform mediump vec2 uAdjustTrans; \n" - "uniform mediump vec2 uAdjustScale; \n" - "uniform lowp ivec2 uCacheFrameBuffer; \n" - "OUT highp vec2 vTexCoord0; \n" - "OUT highp vec2 vTexCoord1; \n" - "OUT mediump vec2 vLodTexCoord; \n" - "OUT lowp float vNumLights; \n" - "OUT lowp vec4 vShadeColor; \n" - "OUT highp vec4 vBaryCoords; \n" - ; - if (!_glinfo.isGLESX || _glinfo.noPerspective) - m_part += "noperspective OUT lowp vec4 vShadeColorNoperspective;\n"; - else - m_part += "OUT lowp vec4 vShadeColorNoperspective; \n"; - m_part += - "void main() \n" - "{ \n" - " gl_Position = aPosition; \n" - " vShadeColor = aColor; \n" - " vec2 texCoord = aTexCoord; \n" - " texCoord *= uTexScale; \n" - " if (uTexturePersp == 0 && aModify[2] == 0.0) texCoord *= 0.5;\n" - " vTexCoord0 = texCoord; \n" - " vTexCoord1 = texCoord; \n" - " vLodTexCoord = texCoord; \n" - " vNumLights = aNumLights; \n" - " if ((aModify[0]) != 0.0) { \n" - " gl_Position.xy *= gl_Position.w; \n" - " } \n" - " else { \n" - " gl_Position.xy = gl_Position.xy * uVScale.xy + uVTrans.xy * gl_Position.ww; \n" - " gl_Position.xy = floor(gl_Position.xy * vec2(4.0)) * vec2(0.25); \n" - " gl_Position.xy = gl_Position.xy * uAdjustScale + gl_Position.ww * uAdjustTrans; \n" - " } \n" - " if ((aModify[1]) != 0.0) \n" - " gl_Position.z *= gl_Position.w; \n" - " if ((aModify[3]) != 0.0) \n" - " vNumLights = 0.0; \n" - " if (uFogUsage > 0) { \n" - " lowp float fp; \n" - " if (aPosition.z < -aPosition.w && aModify[1] == 0.0) \n" - " fp = -uFogScale.s + uFogScale.t; \n" - " else \n" - " fp = aPosition.z/aPosition.w*uFogScale.s + uFogScale.t; \n" - " fp = clamp(fp, 0.0, 1.0); \n" - " if (uFogUsage == 1) \n" - " vShadeColor.a = fp; \n" - " else \n" - " vShadeColor.rgb = vec3(fp); \n" - " } \n" - " vBaryCoords = vec4(aBaryCoords, 1.0 - aBaryCoords.x - aBaryCoords.y, 0.5); \n" - " vShadeColorNoperspective = vShadeColor; \n" - ; - } -}; - -class VertexShaderTriangle : public ShaderPart -{ -public: - VertexShaderTriangle(const opengl::GLInfo & _glinfo) - { - m_part = - "IN highp vec4 aPosition; \n" - "IN lowp vec4 aColor; \n" - "IN lowp float aNumLights; \n" - "IN highp vec4 aModify; \n" - "IN highp vec2 aBaryCoords; \n" - " \n" - "uniform lowp int uFogUsage; \n" - "uniform mediump vec2 uFogScale; \n" - "uniform mediump vec2 uScreenCoordsScale; \n" - "uniform mediump vec2 uVTrans; \n" - "uniform mediump vec2 uVScale; \n" - "uniform mediump vec2 uAdjustTrans; \n" - "uniform mediump vec2 uAdjustScale; \n" - " \n" - "OUT lowp float vNumLights; \n" - "OUT lowp vec4 vShadeColor; \n" - "OUT highp vec4 vBaryCoords; \n" - ; - if (!_glinfo.isGLESX || _glinfo.noPerspective) - m_part += "noperspective OUT lowp vec4 vShadeColorNoperspective;\n"; - else - m_part += "OUT lowp vec4 vShadeColorNoperspective; \n"; - m_part += - " \n" - "void main() \n" - "{ \n" - " gl_Position = aPosition; \n" - " vShadeColor = aColor; \n" - " vNumLights = aNumLights; \n" - " if ((aModify[0]) != 0.0) { \n" - " gl_Position.xy *= gl_Position.w; \n" - " } \n" - " else { \n" - " gl_Position.xy = gl_Position.xy * uVScale.xy + uVTrans.xy * gl_Position.ww; \n" - " gl_Position.xy = floor(gl_Position.xy * vec2(4.0)) * vec2(0.25); \n" - " gl_Position.xy = gl_Position.xy * uAdjustScale + gl_Position.ww * uAdjustTrans; \n" - " } \n" - " if ((aModify[1]) != 0.0) \n" - " gl_Position.z *= gl_Position.w; \n" - " if ((aModify[3]) != 0.0) \n" - " vNumLights = 0.0; \n" - " if (uFogUsage > 0) { \n" - " lowp float fp; \n" - " if (aPosition.z < -aPosition.w && aModify[1] == 0.0) \n" - " fp = -uFogScale.s + uFogScale.t; \n" - " else \n" - " fp = aPosition.z/aPosition.w*uFogScale.s + uFogScale.t; \n" - " fp = clamp(fp, 0.0, 1.0); \n" - " if (uFogUsage == 1) \n" - " vShadeColor.a = fp; \n" - " else \n" - " vShadeColor.rgb = vec3(fp); \n" - " } \n" - " vBaryCoords = vec4(aBaryCoords, 1.0 - aBaryCoords.x - aBaryCoords.y, 0.5); \n" - " vShadeColorNoperspective = vShadeColor; \n" - ; - } -}; - -class VertexShaderTexturedRect : public ShaderPart -{ -public: - VertexShaderTexturedRect(const opengl::GLInfo & _glinfo) - { - m_part = - "IN highp vec4 aRectPosition; \n" - "IN highp vec2 aTexCoord0; \n" - "IN highp vec2 aTexCoord1; \n" - "IN highp vec2 aBaryCoords; \n" - " \n" - "OUT highp vec2 vTexCoord0; \n" - "OUT highp vec2 vTexCoord1; \n" - "OUT lowp vec4 vShadeColor; \n" - "OUT highp vec4 vBaryCoords;" - ; - if (!_glinfo.isGLESX || _glinfo.noPerspective) - m_part += "noperspective OUT lowp vec4 vShadeColorNoperspective;\n"; - else - m_part += "OUT lowp vec4 vShadeColorNoperspective; \n"; - m_part += - "uniform lowp vec4 uRectColor; \n" - "void main() \n" - "{ \n" - " gl_Position = aRectPosition; \n" - " vShadeColor = uRectColor; \n" - " vShadeColorNoperspective = uRectColor; \n" - " vTexCoord0 = aTexCoord0; \n" - " vTexCoord1 = aTexCoord1; \n" - " vBaryCoords = vec4(aBaryCoords, vec2(1.0) - aBaryCoords); \n" - ; - } -}; - -class VertexShaderRect : public ShaderPart -{ -public: - VertexShaderRect(const opengl::GLInfo & _glinfo) - { - m_part = - "IN highp vec4 aRectPosition; \n" - "IN highp vec2 aBaryCoords; \n" - " \n" - "OUT lowp vec4 vShadeColor; \n" - "OUT highp vec4 vBaryCoords; \n" - ; - if (!_glinfo.isGLESX || _glinfo.noPerspective) - m_part += "noperspective OUT lowp vec4 vShadeColorNoperspective;\n"; - else - m_part += "OUT lowp vec4 vShadeColorNoperspective; \n"; - m_part += - "uniform lowp vec4 uRectColor; \n" - "void main() \n" - "{ \n" - " gl_Position = aRectPosition; \n" - " vShadeColor = uRectColor; \n" - " vShadeColorNoperspective = uRectColor; \n" - " vBaryCoords = vec4(aBaryCoords, vec2(1.0) - aBaryCoords);\n" - ; - } -}; - -class VertexShaderEnd : public ShaderPart -{ -public: - VertexShaderEnd(const opengl::GLInfo & _glinfo) - { - if (!_glinfo.isGLESX) { - m_part = - " gl_ClipDistance[0] = gl_Position.w - gl_Position.z; \n" - ; - } else if (config.generalEmulation.enableFragmentDepthWrite != 0 && _glinfo.noPerspective) { - m_part = - " vZCoord = gl_Position.z / gl_Position.w; \n" - " if (uClampMode > 0) \n" - " gl_Position.z = 0.0; \n" - ; - } else if (config.generalEmulation.enableClipping != 0) { - // Move the near plane towards the camera. - // It helps to avoid issues with near-plane clipping in games, which do not use it. - // Z must be scaled back in fragment shader. - m_part = " gl_Position.z /= 8.0; \n"; - } - m_part += - " gl_Position.xy += uVertexOffset * vec2(gl_Position.w); \n" - " gl_Position.xy -= vec2(0.5*screenSizeDims) * gl_Position.ww; \n" - " gl_Position.xy /= vec2(0.5*screenSizeDims); \n" - "} \n" - ; - } -}; - -class FragmentShaderHeader : public ShaderPart -{ -public: - FragmentShaderHeader(const opengl::GLInfo & _glinfo) - { - if (_glinfo.isGLES2) { - m_part = "#version 100 \n"; - if (config.generalEmulation.enableLOD) { - m_part += "#extension GL_EXT_shader_texture_lod : enable \n"; - m_part += "#extension GL_OES_standard_derivatives : enable \n"; - } - m_part += - "#if (__VERSION__ > 120) \n" - "# define IN in \n" - "# define OUT out \n" - "# define texture2D texture \n" - "#else \n" - "# define IN varying \n" - "# define OUT \n" - "#ifndef GL_FRAGMENT_PRECISION_HIGH \n" - "# define highp mediump \n" - "#endif \n" - "#endif // __VERSION __ \n" - ; - } else if (_glinfo.isGLESX) { - std::stringstream ss; - ss << "#version " << Utils::to_string(_glinfo.majorVersion) << Utils::to_string(_glinfo.minorVersion) << "0 es " << std::endl; - if (_glinfo.noPerspective) - ss << "#extension GL_NV_shader_noperspective_interpolation : enable" << std::endl; - if (_glinfo.dual_source_blending) - ss << "#extension GL_EXT_blend_func_extended : enable" << std::endl; - if (_glinfo.ext_fetch) - ss << "#extension GL_EXT_shader_framebuffer_fetch : enable" << std::endl; - if (_glinfo.ext_fetch_arm) - ss << "#extension GL_ARM_shader_framebuffer_fetch : enable" << std::endl; - - if (config.frameBufferEmulation.N64DepthCompare == Config::dcFast) { - if (_glinfo.imageTextures && _glinfo.fragment_interlockNV) { - ss << "#extension GL_NV_fragment_shader_interlock : enable" << std::endl - << "layout(pixel_interlock_ordered) in;" << std::endl; - } - } else if (_glinfo.fetch_depth) - ss << "#extension GL_ARM_shader_framebuffer_fetch_depth_stencil : enable" << std::endl; - - ss << "# define IN in" << std::endl - << "# define OUT out" << std::endl - << "# define texture2D texture" << std::endl; - m_part = ss.str(); - } else { - std::stringstream ss; - ss << "#version " << Utils::to_string(_glinfo.majorVersion) << Utils::to_string(_glinfo.minorVersion) << "0 core " << std::endl; - if (config.frameBufferEmulation.N64DepthCompare != Config::dcDisable) { - if (_glinfo.n64DepthWithFbFetch) - ss << "#extension GL_EXT_shader_framebuffer_fetch : enable" << std::endl; - else if (_glinfo.imageTextures) { - if (_glinfo.majorVersion * 10 + _glinfo.minorVersion < 42) { - ss << "#extension GL_ARB_shader_image_load_store : enable" << std::endl - << "#extension GL_ARB_shading_language_420pack : enable" << std::endl; - } - if (_glinfo.fragment_interlock) - ss << "#extension GL_ARB_fragment_shader_interlock : enable" << std::endl - << "layout(pixel_interlock_ordered) in;" << std::endl; - else if (_glinfo.fragment_interlockNV) - ss << "#extension GL_NV_fragment_shader_interlock : enable" << std::endl - << "layout(pixel_interlock_ordered) in;" << std::endl; - else if (_glinfo.fragment_ordering) - ss << "#extension GL_INTEL_fragment_shader_ordering : enable" << std::endl; - } - } - - ss << "# define IN in" << std::endl - << "# define OUT out" << std::endl - << "# define texture2D texture" << std::endl; - m_part = ss.str(); - } - m_part += - // Return the vector of the standard basis of R^4 with a 1 at position and 0 otherwise. - " #define STVEC(pos) (step(float(pos), vec4(0.5,1.5,2.5,3.5)) - step(float(pos), vec4(-0.5,0.5,1.5,2.5))) \n"; - - std::stringstream ss; - if (_glinfo.isGLES2) - ss << "const mediump float mipmapTileWidth = " << std::setprecision(1) << std::fixed << f32(MIPMAP_TILE_WIDTH) << ";" << std::endl; - else - ss << "const mediump int mipmapTileWidth = " << MIPMAP_TILE_WIDTH << ";" << std::endl; - m_part += ss.str(); - } -}; - -class ShaderBlender1 : public ShaderPart -{ -public: - ShaderBlender1(const opengl::GLInfo & _glinfo) - { -#if 1 - m_part = - " srcColor1 = vec4(0.0); \n" - " dstFactor1 = 0.0; \n" - " muxPM[0] = clampedColor; \n" - " muxA[0] = clampedColor.a; \n" - " muxa = MUXA(uBlendMux1[1]); \n" - " muxB[0] = 1.0 - muxa; \n" - " muxb = MUXB(uBlendMux1[3]); \n" - " muxp = MUXPM(uBlendMux1[0]); \n" - " muxm = MUXPM(uBlendMux1[2]); \n" - " muxaf = MUXF(uBlendMux1[0]); \n" - " muxbf = MUXF(uBlendMux1[2]); \n" - " if (uForceBlendCycle1 != 0) { \n" - " srcColor1 = muxp * muxa + muxm * muxb; \n" - " dstFactor1 = muxaf * muxa + muxbf * muxb; \n" - " srcColor1 = clamp(srcColor1, 0.0, 1.0); \n" - " } else { \n" - " srcColor1 = muxp; \n" - " dstFactor1 = muxaf; \n" - " } \n" - " fragColor = srcColor1; \n" - " fragColor1 = vec4(dstFactor1); \n" - ; -#else - // Keep old code for reference - m_part = - " muxPM[0] = clampedColor; \n" - " if (uForceBlendCycle1 != 0) { \n" - " muxA[0] = clampedColor.a; \n" - " muxB[0] = 1.0 - muxA[uBlendMux1[1]]; \n" - " lowp vec4 blend1 = (muxPM[uBlendMux1[0]] * muxA[uBlendMux1[1]]) + (muxPM[uBlendMux1[2]] * muxB[uBlendMux1[3]]); \n" - " clampedColor.rgb = clamp(blend1.rgb, 0.0, 1.0); \n" - " } else clampedColor.rgb = muxPM[uBlendMux1[0]].rgb; \n" - ; -#endif - } -}; - -class ShaderBlender2 : public ShaderPart -{ -public: - ShaderBlender2(const opengl::GLInfo & _glinfo) - { -#if 1 - m_part = - " srcColor2 = vec4(0.0); \n" - " dstFactor2 = 0.0; \n" - " muxPM[0] = srcColor1; \n" - " muxa = MUXA(uBlendMux2[1]); \n" - " muxB[0] = 1.0 - muxa; \n" - " muxb = MUXB(uBlendMux2[3]); \n" - " muxp = MUXPM(uBlendMux2[0]); \n" - " muxm = MUXPM(uBlendMux2[2]); \n" - " muxF[0] = dstFactor1; \n" - " muxaf = MUXF(uBlendMux2[0]); \n" - " muxbf = MUXF(uBlendMux2[2]); \n" - " if (uForceBlendCycle2 != 0) { \n" - " srcColor2 = muxp * muxa + muxm * muxb; \n" - " dstFactor2 = muxaf * muxa + muxbf * muxb; \n" - " srcColor2 = clamp(srcColor2, 0.0, 1.0); \n" - " } else { \n" - " srcColor2 = muxp; \n" - " dstFactor2 = muxaf; \n" - " } \n" - " fragColor = srcColor2; \n" - " fragColor1 = vec4(dstFactor2); \n" - ; - -#else - // Keep old code for reference - m_part = - " muxPM[0] = clampedColor; \n" - " muxPM[1] = vec4(0.0); \n" - " if (uForceBlendCycle2 != 0) { \n" - " muxA[0] = clampedColor.a; \n" - " muxB[0] = 1.0 - muxA[uBlendMux2[1]]; \n" - " lowp vec4 blend2 = muxPM[uBlendMux2[0]] * muxA[uBlendMux2[1]] + muxPM[uBlendMux2[2]] * muxB[uBlendMux2[3]]; \n" - " clampedColor.rgb = clamp(blend2.rgb, 0.0, 1.0); \n" - " } else clampedColor.rgb = muxPM[uBlendMux2[0]].rgb; \n" - ; -#endif - } -}; - -class ShaderBlenderAlpha : public ShaderPart -{ -public: - ShaderBlenderAlpha(const opengl::GLInfo & _glinfo) - { - if (_glinfo.dual_source_blending || _glinfo.ext_fetch || _glinfo.ext_fetch_arm) { - m_part += - "if (uBlendAlphaMode != 2) { \n" - " lowp vec4 srcAlpha = vec4(cvg, cvg, 1.0, 0.0); \n" - " lowp vec4 dstFactorAlpha = vec4(1.0, 1.0, 0.0, 1.0); \n" - " if (uBlendAlphaMode == 0) \n" - " dstFactorAlpha[0] = 0.0; \n" - " fragColor1.a = dstFactorAlpha[uCvgDest]; \n" - " fragColor.a = srcAlpha[uCvgDest] + lastFragColor.a * fragColor1.a;\n" - "} else fragColor.a = clampedColor.a; \n"; - } - else { - m_part += - "fragColor.a = clampedColor.a;" - ; - } - } -}; - -class ShaderLegacyBlender : public ShaderPart -{ -public: - ShaderLegacyBlender() - { - m_part = - " if (uFogUsage == 1) \n" - " fragColor.rgb = mix(fragColor.rgb, uFogColor.rgb, vShadeColor.a); \n" - ; - } -}; - - -/* -// N64 color wrap and clamp on floats -// See https://github.com/gonetz/GLideN64/issues/661 for reference -if (c < -1.0) return c + 2.0; - -if (c < -0.5) return 1; - -if (c < 0.0) return 0; - -if (c > 2.0) return c - 2.0; - -if (c > 1.5) return 0; - -if (c > 1.0) return 1; - -return c; -*/ -class ShaderClamp : public ShaderPart -{ -public: - ShaderClamp() - { - m_part = - " lowp vec4 wrappedColor = WRAP(cmbRes, -0.51, 1.51); \n" - " lowp vec4 clampedColor = clamp(wrappedColor, 0.0, 1.0); \n" - ; - } -}; - -/* -N64 sign-extension for C component of combiner -if (c > 1.0) -return c - 2.0; - -return c; -*/ -class ShaderSignExtendColorC : public ShaderPart -{ -public: - ShaderSignExtendColorC() - { - m_part = - " color1 = WRAP(color1, -1.01, 1.01); \n" - ; - } -}; - -class ShaderSignExtendAlphaC : public ShaderPart -{ -public: - ShaderSignExtendAlphaC() - { - m_part = - " alpha1 = WRAP(alpha1, -1.01, 1.01); \n" - ; - } -}; - -/* -N64 sign-extension for ABD components of combiner -if (c > 1.5) -return c - 2.0; - -if (c < -0.5) -return c + 2.0; - -return c; -*/ -class ShaderSignExtendColorABD : public ShaderPart -{ -public: - ShaderSignExtendColorABD() - { - m_part = - " color1 = WRAP(color1, -0.51, 1.51); \n" - ; - } -}; - -class ShaderSignExtendAlphaABD : public ShaderPart -{ -public: - ShaderSignExtendAlphaABD() - { - m_part = - " alpha1 = WRAP(alpha1, -0.51,1.51); \n" - ; - } -}; - -class ShaderAlphaTest : public ShaderPart -{ -public: - ShaderAlphaTest() - { - m_part = - " if (uEnableAlphaTest != 0) { \n" - " lowp float alphaTestValue = (uAlphaCompareMode == 3) ? snoise() : uAlphaTestValue; \n" - " lowp float alphaValue; \n" - " if ((uAlphaCvgSel != 0) && (uCvgXAlpha == 0)) { \n" - " alphaValue = 0.125; \n" - " } else { \n" - " alphaValue = clamp(alpha1, 0.0, 1.0); \n" - " } \n" - " if (alphaValue < alphaTestValue) discard; \n" - " } \n" - ; - } -}; - -class ShaderDithering : public ShaderPart -{ -public: - ShaderDithering(const opengl::GLInfo & _glinfo) - { - if (_glinfo.isGLES2) - return; - - if (config.generalEmulation.enableDitheringPattern == 0) { - m_part = - " if (uColorDitherMode == 2) { \n" - " colorDither(snoiseRGB(), clampedColor.rgb); \n" - " } \n" - " if (uAlphaDitherMode == 2) { \n" - " alphaDither(snoiseA(), clampedColor.a); \n" - " } \n" - ; - return; - } - - m_part += - " lowp mat4 bayer = mat4( 0.0, 0.5, 0.125, 0.625, \n" - " 0.5, 0.0, 0.625, 0.125, \n" - " 0.375, 0.875, 0.25, 0.75, \n" - " 0.875, 0.375, 0.75, 0.25); \n" - " lowp mat4 mSquare = mat4( 0.0, 0.75, 0.125, 0.875, \n" - " 0.5, 0.25, 0.625, 0.375, \n" - " 0.375, 0.625, 0.25, 0.5, \n" - " 0.875, 0.125, 0.75, 0.0); \n" - // Try to keep dithering visible even at higher resolutions - " lowp float divider = 1.0 + step(3.0, uScreenScale.x); \n" - " mediump ivec2 position = ivec2(mod((gl_FragCoord.xy - 0.5) / divider,4.0));\n" - " lowp vec4 posX = STVEC(position.x); \n" - " lowp vec4 posY = STVEC(position.y); \n" - " lowp float bayerThreshold = dot(bayer*posY, posX); \n" - " lowp float mSquareThreshold = dot(mSquare*posY, posX); \n" - " switch (uColorDitherMode) { \n" - " case 0: \n" - " colorDither(vec3(mSquareThreshold), clampedColor.rgb); \n" - " break; \n" - " case 1: \n" - " colorDither(vec3(bayerThreshold), clampedColor.rgb); \n" - " break; \n" - " case 2: \n" - " colorDither(snoiseRGB(), clampedColor.rgb); \n" - " break; \n" - " case 3: \n" - " break; \n" - " } \n" - " switch (uAlphaDitherMode) { \n" - " case 0: \n" - " switch (uColorDitherMode) { \n" - " case 0: \n" - " case 2: \n" - " alphaDither(mSquareThreshold, clampedColor.a); \n" - " break; \n" - " case 1: \n" - " case 3: \n" - " alphaDither(bayerThreshold, clampedColor.a); \n" - " break; \n" - " } \n" - " break; \n" - " case 1: \n" - " switch (uColorDitherMode) { \n" - " case 0: \n" - " case 2: \n" - " alphaDither(bayerThreshold, clampedColor.a); \n" - " break; \n" - " case 1: \n" - " case 3: \n" - " alphaDither(mSquareThreshold, clampedColor.a); \n" - " break; \n" - " } \n" - " break; \n" - " case 2: \n" - " alphaDither(snoiseA(), clampedColor.a); \n" - " break; \n" - " case 3: \n" - " break; \n" - " } \n" - ; - } -}; - -class ShaderFragmentGlobalVariablesTex : public ShaderPart -{ -public: - ShaderFragmentGlobalVariablesTex(const opengl::GLInfo & _glinfo) - { - m_part = - "uniform sampler2D uTex0; \n" - "uniform sampler2D uTex1; \n" - "uniform lowp vec4 uFogColor; \n" - "uniform lowp vec4 uCenterColor;\n" - "uniform lowp vec4 uScaleColor; \n" - "uniform lowp vec4 uBlendColor; \n" - "uniform lowp vec4 uEnvColor; \n" - "uniform lowp vec4 uPrimColor; \n" - "uniform lowp float uPrimLod; \n" - "uniform lowp float uK4; \n" - "uniform lowp float uK5; \n" - "uniform lowp int uAlphaCompareMode; \n" - "uniform lowp ivec2 uFbMonochrome; \n" - "uniform lowp ivec2 uFbFixedAlpha; \n" - "uniform lowp int uEnableAlphaTest; \n" - "uniform lowp int uCvgXAlpha; \n" - "uniform lowp int uAlphaCvgSel; \n" - "uniform lowp float uAlphaTestValue; \n" - "uniform lowp int uDepthSource; \n" - "uniform highp float uPrimDepth; \n" - "uniform mediump vec2 uScreenScale; \n" - "uniform highp vec2 uTexClamp[2]; \n" - "uniform highp vec2 uTexWrap[2]; \n" - "uniform lowp vec2 uTexWrapEn[2]; \n" - "uniform lowp vec2 uTexMirrorEn[2]; \n" - "uniform lowp vec2 uTexClampEn[2]; \n" - "uniform highp vec2 uTexSize[2]; \n" - "uniform highp vec2 uShiftScale[2]; \n" - "uniform highp vec2 uTexOffset[2]; \n" - "uniform highp vec2 uHDRatio[2]; \n" - "uniform highp vec2 uTexCoordOffset[2]; \n" - "uniform highp vec2 uBilinearOffset; \n" - "uniform highp vec2 uCacheOffset[2]; \n" - "uniform lowp int uUseTexCoordBounds; \n" - "uniform highp vec4 uTexCoordBounds0; \n" - "uniform highp vec4 uTexCoordBounds1; \n" - "uniform lowp int uScreenSpaceTriangle; \n" - "highp vec2 texCoord0; \n" - "highp vec2 texCoord1; \n" - "highp vec2 tcData0[5]; \n" - "highp vec2 tcData1[5]; \n" - "uniform lowp int uCvgDest; \n" - "uniform lowp int uBlendAlphaMode; \n" - "lowp float cvg; \n" - ; - - if (config.generalEmulation.enableLegacyBlending != 0) { - m_part += - "uniform lowp int uFogUsage; \n" - ; - } else { - m_part += - "uniform lowp ivec4 uBlendMux1; \n" - "uniform lowp int uForceBlendCycle1;\n" - ; - } - - if (!_glinfo.isGLES2) { - m_part += - "uniform sampler2D uDepthTex; \n" - "uniform lowp int uAlphaDitherMode; \n" - "uniform lowp int uColorDitherMode; \n" - "uniform lowp int uRenderTarget; \n" - "uniform mediump vec2 uDepthScale; \n" - ; - if (config.frameBufferEmulation.N64DepthCompare != Config::dcDisable) { - m_part += - "uniform lowp int uEnableDepthCompare; \n" - ; - } - } else { - m_part += - "lowp int nCurrentTile; \n" - ; - } - - if (config.video.multisampling > 0) { - m_part += - "uniform lowp ivec2 uMSTexEnabled; \n" - "uniform lowp sampler2DMS uMSTex0; \n" - "uniform lowp sampler2DMS uMSTex1; \n" - ; - } - - if (!_glinfo.isGLESX || _glinfo.noPerspective) - m_part += "noperspective IN lowp vec4 vShadeColorNoperspective; \n"; - else - m_part += "IN lowp vec4 vShadeColorNoperspective; \n"; - - m_part += - "IN lowp vec4 vShadeColor; \n" - "IN highp vec2 vTexCoord0; \n" - "IN highp vec2 vTexCoord1; \n" - "IN mediump vec2 vLodTexCoord; \n" - "IN lowp float vNumLights; \n" - "IN highp vec4 vBaryCoords; \n" - ; - - if (_glinfo.dual_source_blending) { - m_part += - "layout(location = 0, index = 0) OUT lowp vec4 fragColor; \n" // MAIN FRAGMENT SHADER OUTPUT - "layout(location = 0, index = 1) OUT lowp vec4 fragColor1; \n" // SECONDARY FRAGMENT SHADER OUTPUT - "#define LAST_FRAG_COLOR vec4(0.0) \n" // DUMMY - "#define LAST_FRAG_ALPHA 1.0 \n" // DUMMY - ; - } else if (_glinfo.ext_fetch) { - m_part += - "layout(location = 0) inout lowp vec4 fragColor; \n" // MAIN FRAGMENT SHADER OUTPUT - "lowp vec4 fragColor1; \n" // DUMMY - "#define LAST_FRAG_COLOR fragColor \n" // CURRENT FRAMEBUFFER COLOR/ALPHA - "#define LAST_FRAG_ALPHA fragColor.a \n" // CURRENT FRAMEBUFFER ALPHA - ; - } else if (_glinfo.ext_fetch_arm) { - m_part += - "OUT lowp vec4 fragColor; \n" // MAIN FRAGMENT SHADER OUTPUT - "lowp vec4 fragColor1; \n" // DUMMY - "#define LAST_FRAG_COLOR gl_LastFragColorARM \n" // CURRENT FRAMEBUFFER COLOR/ALPHA - "#define LAST_FRAG_ALPHA gl_LastFragColorARM.a \n" // CURRENT FRAMEBUFFER ALPHA - ; - } else { - m_part += - "OUT lowp vec4 fragColor; \n" // MAIN FRAGMENT SHADER OUTPUT - "lowp vec4 fragColor1; \n" // DUMMY - "#define LAST_FRAG_COLOR vec4(0.0) \n" // DUMMY - "#define LAST_FRAG_ALPHA 1.0 \n" // DUMMY - ; - } - - if (config.frameBufferEmulation.N64DepthCompare == Config::dcFast && _glinfo.n64DepthWithFbFetch) { - m_part += - "layout(location = 1) inout highp vec4 depthZ; \n" - "layout(location = 2) inout highp vec4 depthDeltaZ; \n" - ; - } - - if (_glinfo.isGLES2) - m_part += - "uniform mediump vec2 uTextureSize[2]; \n" - ; - } -}; - -class ShaderFragmentGlobalVariablesNotex : public ShaderPart -{ -public: - ShaderFragmentGlobalVariablesNotex(const opengl::GLInfo & _glinfo) - { - m_part = - "uniform lowp vec4 uFogColor; \n" - "uniform lowp vec4 uCenterColor;\n" - "uniform lowp vec4 uScaleColor; \n" - "uniform lowp vec4 uBlendColor; \n" - "uniform lowp vec4 uEnvColor; \n" - "uniform lowp vec4 uPrimColor; \n" - "uniform lowp float uPrimLod; \n" - "uniform lowp float uK4; \n" - "uniform lowp float uK5; \n" - "uniform lowp int uAlphaCompareMode; \n" - "uniform lowp ivec2 uFbMonochrome; \n" - "uniform lowp ivec2 uFbFixedAlpha; \n" - "uniform lowp int uEnableAlphaTest; \n" - "uniform lowp int uCvgXAlpha; \n" - "uniform lowp int uAlphaCvgSel; \n" - "uniform lowp float uAlphaTestValue; \n" - "uniform lowp int uDepthSource; \n" - "uniform highp float uPrimDepth; \n" - "uniform mediump vec2 uScreenScale; \n" - "uniform lowp int uScreenSpaceTriangle; \n" - "uniform lowp int uCvgDest; \n" - "uniform lowp int uBlendAlphaMode; \n" - "lowp float cvg; \n" - ; - - if (config.generalEmulation.enableLegacyBlending != 0) { - m_part += - "uniform lowp int uFogUsage; \n" - ; - } else { - m_part += - "uniform lowp ivec4 uBlendMux1; \n" - "uniform lowp int uForceBlendCycle1;\n" - ; - } - - if (!_glinfo.isGLES2) { - m_part += - "uniform sampler2D uDepthTex; \n" - "uniform lowp int uAlphaDitherMode; \n" - "uniform lowp int uColorDitherMode; \n" - "uniform lowp int uRenderTarget; \n" - "uniform mediump vec2 uDepthScale; \n" - ; - if (config.frameBufferEmulation.N64DepthCompare != Config::dcDisable) { - m_part += - "uniform lowp int uEnableDepthCompare; \n" - ; - } - } else { - m_part += - "lowp int nCurrentTile; \n" - ; - } - - if (!_glinfo.isGLESX || _glinfo.noPerspective) - m_part += "noperspective IN lowp vec4 vShadeColorNoperspective; \n"; - else - m_part += "IN lowp vec4 vShadeColorNoperspective; \n"; - - m_part += - "IN lowp vec4 vShadeColor; \n" - "IN lowp float vNumLights; \n" - "IN highp vec4 vBaryCoords; \n" - ; - - if (_glinfo.dual_source_blending) { - m_part += - "layout(location = 0, index = 0) OUT lowp vec4 fragColor; \n" // MAIN FRAGMENT SHADER OUTPUT - "layout(location = 0, index = 1) OUT lowp vec4 fragColor1; \n" // SECONDARY FRAGMENT SHADER OUTPUT - "#define LAST_FRAG_COLOR vec4(0.0) \n" // DUMMY - "#define LAST_FRAG_ALPHA 1.0 \n" // DUMMY - ; - } else if (_glinfo.ext_fetch) { - m_part += - "layout(location = 0) inout lowp vec4 fragColor; \n" // MAIN FRAGMENT SHADER OUTPUT - "lowp vec4 fragColor1; \n" // DUMMY - "#define LAST_FRAG_COLOR fragColor \n" // CURRENT FRAMEBUFFER COLOR/ALPHA - "#define LAST_FRAG_ALPHA fragColor.a \n" // CURRENT FRAMEBUFFER ALPHA - ; - } else if (_glinfo.ext_fetch_arm) { - m_part += - "OUT lowp vec4 fragColor; \n" // MAIN FRAGMENT SHADER OUTPUT - "lowp vec4 fragColor1; \n" // DUMMY - "#define LAST_FRAG_COLOR gl_LastFragColorARM \n" // CURRENT FRAMEBUFFER COLOR/ALPHA - "#define LAST_FRAG_ALPHA gl_LastFragColorARM.a \n" // CURRENT FRAMEBUFFER ALPHA - ; - } else { - m_part += - "OUT lowp vec4 fragColor; \n" // MAIN FRAGMENT SHADER OUTPUT - "lowp vec4 fragColor1; \n" // DUMMY - "#define LAST_FRAG_COLOR vec4(0.0) \n" // DUMMY - "#define LAST_FRAG_ALPHA 1.0 \n" // DUMMY - ; - } - - if (config.frameBufferEmulation.N64DepthCompare == Config::dcFast && _glinfo.n64DepthWithFbFetch) { - m_part += - "layout(location = 1) inout highp vec4 depthZ; \n" - "layout(location = 2) inout highp vec4 depthDeltaZ; \n" - ; - } - } -}; - -class ShaderFragmentHeaderNoise : public ShaderPart -{ -public: - ShaderFragmentHeaderNoise(const opengl::GLInfo & _glinfo) - { - m_part = - "lowp float snoise();\n" - ; - } -}; - -class ShaderFragmentHeaderWriteDepth : public ShaderPart -{ -public: - ShaderFragmentHeaderWriteDepth(const opengl::GLInfo & _glinfo) - { - if (!_glinfo.isGLES2) { - m_part = - "highp float writeDepth();\n"; - ; - } - if (_glinfo.isGLESX && _glinfo.noPerspective) { - m_part = - "noperspective IN highp float vZCoord; \n" - "uniform lowp float uPolygonOffset; \n" - "uniform lowp int uClampMode; \n" - + m_part - ; - } - - } -}; - -class ShaderFragmentHeaderCalcLight : public ShaderPart -{ -public: - ShaderFragmentHeaderCalcLight(const opengl::GLInfo & _glinfo) - { - m_part = - "void calc_light(in lowp float fLights, in lowp vec3 input_color, out lowp vec3 output_color);\n"; - ; - } -}; - -class ShaderFragmentHeaderMipMap : public ShaderPart -{ -public: - ShaderFragmentHeaderMipMap(const opengl::GLInfo & _glinfo) - { - m_part = - "mediump float mipmap(out lowp vec4 readtex0, out lowp vec4 readtex1);\n"; - ; - } -}; - -class ShaderFragmentHeaderTextureEngine : public ShaderPart -{ -public: - ShaderFragmentHeaderTextureEngine(const opengl::GLInfo & _glinfo) - { - m_part = - "highp vec2 clampWrapMirror(in highp vec2 vTexCoord, \n" - " in highp vec2 vWrap, in highp vec2 vClamp, \n" - " in lowp vec2 vClampEn, in lowp vec2 vMirrorEn ); \n" - "void textureEngine0(in highp vec2 texCoord, out highp vec2 tcData[5]); \n" - "void textureEngine1(in highp vec2 texCoord, out highp vec2 tcData[5]); \n" - ; - } -}; - -class ShaderFragmentHeaderReadMSTex : public ShaderPart -{ -public: - ShaderFragmentHeaderReadMSTex(const opengl::GLInfo & _glinfo) : m_glinfo(_glinfo) - { - } - - void write(std::stringstream & shader) const override - { - if (!m_glinfo.isGLES2 && - config.video.multisampling > 0 && - (g_cycleType == G_CYC_COPY || g_textureConvert.useTextureFiltering())) - { - shader << - "lowp vec4 readTexMS(in lowp sampler2DMS mstex, in highp vec2 tcData[5], in lowp int fbMonochrome, in lowp int fbFixedAlpha);\n"; - } - } - -private: - const opengl::GLInfo& m_glinfo; -}; - -class ShaderFragmentHeaderDither : public ShaderPart -{ -public: - ShaderFragmentHeaderDither(const opengl::GLInfo & _glinfo) - { - if (_glinfo.isGLES2) - return; - - m_part = - "void colorDither(in lowp vec3 _threshold, inout lowp vec3 _color);\n" - "void alphaDither(in lowp float _threshold, inout lowp float _alpha);\n" - "lowp vec3 snoiseRGB();\n" - "lowp float snoiseA();\n" - ; - } -}; - -class ShaderFragmentHeaderDepthCompare : public ShaderPart -{ -public: - ShaderFragmentHeaderDepthCompare(const opengl::GLInfo & _glinfo) - { - if (config.frameBufferEmulation.N64DepthCompare != Config::dcDisable) { - m_part = - "bool depth_compare(highp float curZ); \n" - "bool depth_render(highp float Z, highp float curZ); \n" - ; - if (_glinfo.imageTextures & !_glinfo.n64DepthWithFbFetch) { - m_part += - "layout(binding = 2, r32f) highp uniform restrict image2D uDepthImageZ; \n" - "layout(binding = 3, r32f) highp uniform restrict image2D uDepthImageDeltaZ; \n" - ; - } - } - } -}; - -class ShaderFragmentHeaderReadTex : public ShaderPart -{ -public: - ShaderFragmentHeaderReadTex(const opengl::GLInfo & _glinfo) : m_glinfo(_glinfo) - { - } - - void write(std::stringstream & shader) const override - { - std::string shaderPart; - if (!m_glinfo.isGLES2) { - - if (g_textureConvert.useTextureFiltering()) { - shaderPart += "uniform lowp int uTextureFilterMode; \n"; - shaderPart += "#define TEX_NEAREST(name, tex, tcData) \\\n" - "{ \\\n" - " name = texelFetch(tex, ivec2(tcData[0]), 0); \\\n" - "} \n" - ; - switch (config.texture.bilinearMode + config.texture.enableHalosRemoval * 2) { - case BILINEAR_3POINT: - // 3 point texture filtering. - // Original author: ArthurCarvalho - // GLSL implementation: twinaphex, mupen64plus-libretro project. - shaderPart += - "#define TEX_FILTER(name, tex, tcData) \\\n" - " { \\\n" - " lowp float bottomRightTri = step(1.0, tcData[4].s + tcData[4].t); \\\n" - " lowp vec4 c00 = texelFetch(tex, ivec2(tcData[0]), 0); \\\n" - " lowp vec4 c01 = texelFetch(tex, ivec2(tcData[1]), 0); \\\n" - " lowp vec4 c10 = texelFetch(tex, ivec2(tcData[2]), 0); \\\n" - " lowp vec4 c11 = texelFetch(tex, ivec2(tcData[3]), 0); \\\n" - " lowp vec4 c0 = c00 + tcData[4].s*(c10-c00) + tcData[4].t*(c01-c00); \\\n" - " lowp vec4 c1 = c11 + (1.0-tcData[4].s)*(c01-c11) + (1.0-tcData[4].t)*(c10-c11); \\\n" - " name = c0 + bottomRightTri * (c1-c0); \\\n" - " } \n" - ; - break; - case BILINEAR_STANDARD: - shaderPart += - "#define TEX_FILTER(name, tex, tcData) \\\n" - "{ \\\n" - " lowp vec4 c00 = texelFetch(tex, ivec2(tcData[0]), 0); \\\n" - " lowp vec4 c01 = texelFetch(tex, ivec2(tcData[1]), 0); \\\n" - " lowp vec4 c10 = texelFetch(tex, ivec2(tcData[2]), 0); \\\n" - " lowp vec4 c11 = texelFetch(tex, ivec2(tcData[3]), 0); \\\n" - " lowp vec4 c0 = c00 + tcData[4].s * (c10-c00); \\\n" - " lowp vec4 c1 = c01 + tcData[4].s * (c11-c01); \\\n" - " name = c0 + tcData[4].t * (c1-c0); \\\n" - "} \n" - ; - break; - case BILINEAR_3POINT_WITH_COLOR_BLEEDING: - // 3 point texture filtering. - // Original author: ArthurCarvalho - // GLSL implementation: twinaphex, mupen64plus-libretro project. - shaderPart += - "#define TEX_FILTER(name, tex, tcData) \\\n" - "{ \\\n" - " lowp float bottomRightTri = step(1.0, tcData[4].s + tcData[4].t); \\\n" - " lowp vec4 c00 = texelFetch(tex, ivec2(tcData[0]), 0); \\\n" - " lowp vec4 c01 = texelFetch(tex, ivec2(tcData[1]), 0); \\\n" - " lowp vec4 c10 = texelFetch(tex, ivec2(tcData[2]), 0); \\\n" - " lowp vec4 c11 = texelFetch(tex, ivec2(tcData[3]), 0); \\\n" - " if(uEnableAlphaTest == 1 ){ \\\n" // Calculate premultiplied color values - " c00.rgb *= c00.a; \\\n" - " c01.rgb *= c01.a; \\\n" - " c10.rgb *= c10.a; \\\n" - " c11.rgb *= c11.a; \\\n" - " } \\\n" - " lowp vec4 c0 = c00 + tcData[4].s*(c10-c00) + tcData[4].t*(c01-c00); \\\n" - " lowp vec4 c1 = c11 + (1.0-tcData[4].s)*(c01-c11) + (1.0-tcData[4].t)*(c10-c11); \\\n" - " name = c0 + bottomRightTri * (c1-c0); \\\n" - " if(uEnableAlphaTest == 1 ) name.rgb /= name.a; \\\n" // Divide alpha to get actual color value - "} \n" - ; - break; - case BILINEAR_STANDARD_WITH_COLOR_BLEEDING_AND_PREMULTIPLIED_ALPHA: - shaderPart += - "#define TEX_FILTER(name, tex, tcData) \\\n" - "{ \\\n" - " lowp vec4 c00 = texelFetch(tex, ivec2(tcData[0]), 0); \\\n" - " lowp vec4 c01 = texelFetch(tex, ivec2(tcData[1]), 0); \\\n" - " lowp vec4 c10 = texelFetch(tex, ivec2(tcData[2]), 0); \\\n" - " lowp vec4 c11 = texelFetch(tex, ivec2(tcData[3]), 0); \\\n" - " if(uEnableAlphaTest == 1){ \\\n" // Calculate premultiplied color values - " c00.rgb *= c00.a; \\\n" - " c01.rgb *= c01.a; \\\n" - " c10.rgb *= c10.a; \\\n" - " c11.rgb *= c11.a; \\\n" - " } \\\n" - " lowp vec4 c0 = c00 + tcData[4].s * (c10-c00); \\\n" - " lowp vec4 c1 = c01 + tcData[4].s * (c11-c01); \\\n" - " name = c0 + tcData[4].t * (c1-c0); \\\n" - " if(uEnableAlphaTest == 1) name.rgb /= name.a; \\\n" - "} \n" - ; - break; - } - shaderPart += - "#define READ_TEX(name, tex, tcData, fbMonochrome, fbFixedAlpha) \\\n" - " { \\\n" - " if (fbMonochrome == 3) { \\\n" - " mediump ivec2 coord = ivec2(gl_FragCoord.xy); \\\n" - " name = texelFetch(tex, coord, 0); \\\n" - " } else { \\\n" - " if (uTextureFilterMode == 0) \\\n" - " { \\\n" - " TEX_NEAREST(name, tex, tcData); \\\n" - " } \\\n" - " else TEX_FILTER(name, tex, tcData); \\\n" - " } \\\n" - " if (fbMonochrome == 1) name = vec4(name.r); \\\n" - " else if (fbMonochrome == 2) \\\n" - " name.rgb = vec3(dot(vec3(0.2126, 0.7152, 0.0722), name.rgb)); \\\n" - " else if (fbMonochrome == 3) { \\\n" - " name.rgb = vec3(dot(vec3(0.2126, 0.7152, 0.0722), name.rgb)); \\\n" - " name.a = 0.0; \\\n" - " } \\\n" - " if (fbFixedAlpha == 1) name.a = 0.825; \\\n" - " } \n" - ; - } - - if (g_textureConvert.useYUVCoversion()) { - shaderPart += - "uniform lowp ivec2 uTextureFormat; \n" - "uniform lowp int uTextureConvert; \n" - "uniform mediump ivec4 uConvertParams; \n" - "#define YUVCONVERT(name, format) \\\n" - " mediump ivec4 icolor = ivec4(name*255.0); \\\n" - " if (format == 1) \\\n" - " icolor.rg -= 128; \\\n" - " mediump ivec4 iconvert; \\\n" - " iconvert.r = icolor.b + (uConvertParams[0]*icolor.g + 128)/256; \\\n" - " iconvert.g = icolor.b + (uConvertParams[1]*icolor.r + uConvertParams[2]*icolor.g + 128)/256; \\\n" - " iconvert.b = icolor.b + (uConvertParams[3]*icolor.r + 128)/256; \\\n" - " iconvert.a = icolor.b; \\\n" - " name = vec4(iconvert)/255.0; \n" - "#define YUVCONVERT_TEX0(name, tex, tcData, format) \\\n" - " { \\\n" - " name = texelFetch(tex, ivec2(tcData[0]), 0); \\\n" - " YUVCONVERT(name, format) \\\n" - " } \n" - "#define YUVCONVERT_TEX1(name, tex, tcData, format, prev) \\\n" - " { \\\n" - " if (uTextureConvert != 0) name = prev; \\\n" - " else name = texelFetch(tex, ivec2(tcData[0]), 0); \\\n" - " YUVCONVERT(name, format) \\\n" - " } \n" - ; - } - - } else { - if (g_textureConvert.useTextureFiltering()) { - shaderPart += - "uniform lowp int uTextureFilterMode; \n" - "lowp vec4 readTex(in sampler2D tex, in highp vec2 tcData[5], in lowp int fbMonochrome, in lowp int fbFixedAlpha); \n" - ; - } - if (g_textureConvert.useYUVCoversion()) { - shaderPart += - "uniform lowp ivec2 uTextureFormat; \n" - "uniform lowp int uTextureConvert; \n" - "uniform mediump ivec4 uConvertParams; \n" - "lowp vec4 YUV_Convert(in sampler2D tex, in highp vec2 tcData[5], in lowp int convert, in lowp int format, in lowp vec4 prev); \n" - ; - } - } - - shader << shaderPart; - } - -private: - const opengl::GLInfo& m_glinfo; -}; - -class ShaderFragmentHeaderReadTexCopyMode : public ShaderPart -{ -public: - ShaderFragmentHeaderReadTexCopyMode (const opengl::GLInfo & _glinfo) - { - if (!_glinfo.isGLES2) { - m_part = - "#define READ_TEX(name, tex, tcData, fbMonochrome, fbFixedAlpha) \\\n" - " { \\\n" - " if (fbMonochrome == 3) { \\\n" - " mediump ivec2 coord = ivec2(gl_FragCoord.xy); \\\n" - " name = texelFetch(tex, coord, 0); \\\n" - " } else { \\\n" - " name = texelFetch(tex, ivec2(tcData[0]),0); \\\n" - " } \\\n" - " if (fbMonochrome == 1) name = vec4(name.r); \\\n" - " else if (fbMonochrome == 2) \\\n" - " name.rgb = vec3(dot(vec3(0.2126, 0.7152, 0.0722), name.rgb)); \\\n" - " else if (fbMonochrome == 3) { \\\n" - " name.rgb = vec3(dot(vec3(0.2126, 0.7152, 0.0722), name.rgb)); \\\n" - " name.a = 0.0; \\\n" - " } \\\n" - " if (fbFixedAlpha == 1) name.a = 0.825; \\\n" - " } \n" - ; - } else { - m_part = - "lowp vec4 readTex(in sampler2D tex, in highp vec2 tcData[5], in lowp int fbMonochrome, in lowp int fbFixedAlpha); \n" - ; - } - } -}; - -class ShaderFragmentMain : public ShaderPart -{ -public: - ShaderFragmentMain(const opengl::GLInfo & _glinfo) - { - m_part = - "void main() \n" - "{ \n" - ; - if (!_glinfo.isGLES2) { - m_part += - " highp float fragDepth = writeDepth(); \n" - ; - } - m_part += - " lowp vec4 vec_color; \n" - " lowp float alpha1; \n" - " lowp vec3 color1, input_color; \n" - ; - if (config.generalEmulation.enableClipping != 0) - m_part += - " lowp vec4 shadeColor = vShadeColorNoperspective; \n" - ; - else - m_part += - " lowp vec4 shadeColor = uScreenSpaceTriangle == 0 ? vShadeColor : vShadeColorNoperspective; \n" - ; - - m_part += "#define WRAP(x, low, high) (mod((x)-(low), (high)-(low)) + (low)) \n"; // Return wrapped value of x in interval [low, high) - // m_part += "#define WRAP(x, low, high) (x) - ((high)-(low)) * floor(((x)-(low))/((high)-(low))) \n"; // Perhaps more compatible? - // m_part += "#define WRAP(x, low, high) (x) + ((high)-(low)) * (1.0-step(low,x)) - ((high)-(low)) * step(high,x) \n"; // Step based version. Only wraps correctly if input is in the range [low-(high-low), high + (high-low)). Similar to old code. - } - -}; - -class ShaderFragmentMain2Cycle : public ShaderPart -{ -public: - ShaderFragmentMain2Cycle(const opengl::GLInfo & _glinfo) - { - m_part = - "void main() \n" - "{ \n" - ; - if (!_glinfo.isGLES2) { - m_part += - " highp float fragDepth = writeDepth(); \n" - ; - } - m_part += - " lowp vec4 vec_color, combined_color; \n" - " lowp float alpha1, alpha2; \n" - " lowp vec3 color1, color2, input_color; \n" - ; - if (config.generalEmulation.enableClipping != 0) - m_part += - " lowp vec4 shadeColor = vShadeColorNoperspective; \n" - ; - else - m_part += - " lowp vec4 shadeColor = uScreenSpaceTriangle == 0 ? vShadeColor : vShadeColorNoperspective; \n" - ; - - m_part += "#define WRAP(x, low, high) mod((x)-(low), (high)-(low)) + (low) \n"; // Return wrapped value of x in interval [low, high) - // m_part += "#define WRAP(x, low, high) (x) - ((high)-(low)) * floor(((x)-(low))/((high)-(low))) \n"; // Perhaps more compatible? - // m_part += "#define WRAP(x, low, high) (x) + (2.0) * (1.0-step(low,x)) - (2.0) * step(high,x) \n"; // Step based version. Only wraps correctly if input is in the range [low-(high-low), high + (high-low)). Similar to old code. - } -}; - -class ShaderFragmentBlendMux : public ShaderPart -{ -public: - ShaderFragmentBlendMux(const opengl::GLInfo & _glinfo) - { - if (config.generalEmulation.enableLegacyBlending == 0) { - m_part = - " #define MUXA(pos) dot(muxA, STVEC(pos)) \n" - " #define MUXB(pos) dot(muxB, STVEC(pos)) \n" - " #define MUXPM(pos) muxPM*(STVEC(pos)) \n" - " #define MUXF(pos) dot(muxF, STVEC(pos)) \n" - " lowp vec4 lastFragColor = LAST_FRAG_COLOR; \n" - " lowp float lastFragAlpha = LAST_FRAG_ALPHA; \n" - " lowp mat4 muxPM = mat4(vec4(0.0), lastFragColor, uBlendColor, uFogColor); \n" - " lowp vec4 muxA = vec4(0.0, uFogColor.a, shadeColor.a, 0.0); \n" - " lowp vec4 muxB = vec4(0.0, lastFragAlpha, 1.0, 0.0); \n" - " lowp vec4 muxF = vec4(0.0, 1.0, 0.0, 0.0); \n" - " lowp vec4 muxp, muxm, srcColor1, srcColor2; \n" - " lowp float muxa, muxb, dstFactor1, dstFactor2, muxaf, muxbf; \n" - ; - } - } -}; - -class ShaderFragmentReadTexMipmap : public ShaderPart -{ -public: - ShaderFragmentReadTexMipmap(const opengl::GLInfo & _glinfo) - { - m_part = - " lowp vec4 readtex0, readtex1; \n" - " lowp float lod_frac = mipmap(readtex0, readtex1); \n" - ; - } -}; - -class ShaderFragmentReadTexCopyMode : public ShaderPart -{ -public: - ShaderFragmentReadTexCopyMode(const opengl::GLInfo & _glinfo) - { - if (_glinfo.isGLES2) { - m_part = - " nCurrentTile = 0; \n" - " lowp vec4 readtex0 = readTex(uTex0, tcData0, uFbMonochrome[0], uFbFixedAlpha[0]); \n" - ; - } else { - if (config.video.multisampling > 0) { - m_part = - " lowp vec4 readtex0; \n" - " if (uMSTexEnabled[0] == 0) { \n" - " READ_TEX(readtex0, uTex0, tcData0, uFbMonochrome[0], uFbFixedAlpha[0]) \n" - " } else readtex0 = readTexMS(uMSTex0, tcData0, uFbMonochrome[0], uFbFixedAlpha[0]);\n" - ; - } else { - m_part = - " lowp vec4 readtex0; \n" - " READ_TEX(readtex0, uTex0, tcData0, uFbMonochrome[0], uFbFixedAlpha[0]) \n" - ; - } - } - } -}; - -class ShaderFragmentReadTex0 : public ShaderPart -{ -public: - ShaderFragmentReadTex0(const opengl::GLInfo & _glinfo) : m_glinfo(_glinfo) - { - } - - void write(std::stringstream & shader) const override - { - std::string shaderPart; - - if (m_glinfo.isGLES2) { - - shaderPart = " nCurrentTile = 0; \n"; - if (g_textureConvert.getBilerp0()) { - shaderPart += " lowp vec4 readtex0 = readTex(uTex0, tcData0, uFbMonochrome[0], uFbFixedAlpha[0]); \n"; - } else { - shaderPart += " lowp vec4 tmpTex = vec4(0.0); \n" - " lowp vec4 readtex0 = YUV_Convert(uTex0, tcData0, 0, uTextureFormat[0], tmpTex); \n"; - } - - } else { - - if (!g_textureConvert.getBilerp0()) { - shaderPart = " lowp vec4 readtex0; \n" - " YUVCONVERT_TEX0(readtex0, uTex0, tcData0, uTextureFormat[0]) \n"; - } else { - if (config.video.multisampling > 0) { - shaderPart = - " lowp vec4 readtex0; \n" - " if (uMSTexEnabled[0] == 0) { \n" - " READ_TEX(readtex0, uTex0, tcData0, uFbMonochrome[0], uFbFixedAlpha[0]) \n" - " } else readtex0 = readTexMS(uMSTex0, tcData0, uFbMonochrome[0], uFbFixedAlpha[0]); \n"; - } else { - shaderPart = " lowp vec4 readtex0; \n" - " READ_TEX(readtex0, uTex0, tcData0, uFbMonochrome[0], uFbFixedAlpha[0]) \n"; - } - } - - } - - shader << shaderPart; - } - -private: - const opengl::GLInfo& m_glinfo; -}; - -class ShaderFragmentReadTex1 : public ShaderPart -{ -public: - ShaderFragmentReadTex1(const opengl::GLInfo & _glinfo) : m_glinfo(_glinfo) - { - } - - void write(std::stringstream & shader) const override - { - std::string shaderPart; - - if (m_glinfo.isGLES2) { - - shaderPart = " nCurrentTile = 1; \n"; - - if (g_textureConvert.getBilerp1()) { - shaderPart += " lowp vec4 readtex1 = readTex(uTex1, tcData1, uFbMonochrome[1], uFbFixedAlpha[1]); \n"; - } else { - shaderPart += " lowp vec4 readtex1 = YUV_Convert(uTex1, tcData1, uTextureConvert, uTextureFormat[1], readtex0); \n"; - } - - } else { - - if (!g_textureConvert.getBilerp1()) { - shaderPart = - " lowp vec4 readtex1; \n" - " YUVCONVERT_TEX1(readtex1, uTex1, tcData1, uTextureFormat[1], readtex0) \n"; - } else { - if (config.video.multisampling > 0) { - shaderPart = - " lowp vec4 readtex1; \n" - " if (uMSTexEnabled[1] == 0) { \n" - " READ_TEX(readtex1, uTex1, tcData1, uFbMonochrome[1], uFbFixedAlpha[1]) \n" - " } else readtex1 = readTexMS(uMSTex1, tcData1, uFbMonochrome[1], uFbFixedAlpha[1]); \n"; - } else { - shaderPart = " lowp vec4 readtex1; \n" - " READ_TEX(readtex1, uTex1, tcData1, uFbMonochrome[1], uFbFixedAlpha[1]) \n"; - - } - } - - } - - shader << shaderPart; - } - -private: - const opengl::GLInfo& m_glinfo; -}; - -class ShaderFragmentCallN64Depth : public ShaderPart -{ -public: - ShaderFragmentCallN64Depth(const opengl::GLInfo & _glinfo) - { - if (config.frameBufferEmulation.N64DepthCompare != Config::dcDisable) { - m_part = " bool should_discard = false; \n"; - - if (_glinfo.imageTextures && !_glinfo.n64DepthWithFbFetch) { - if (_glinfo.fragment_interlock) - m_part += " beginInvocationInterlockARB(); \n"; - else if (_glinfo.fragment_interlockNV) - m_part += " beginInvocationInterlockNV(); \n"; - else if (_glinfo.fragment_ordering) - m_part += " beginFragmentShaderOrderingINTEL(); \n"; - } - - m_part += - " if (uRenderTarget != 0) { if (!depth_render(fragColor.r, fragDepth)) should_discard = true; } \n" - " else if (!depth_compare(fragDepth)) should_discard = true; \n" - ; - - if (_glinfo.imageTextures & !_glinfo.n64DepthWithFbFetch) { - if (_glinfo.fragment_interlock) - m_part += " endInvocationInterlockARB(); \n"; - else if (_glinfo.fragment_interlockNV) - m_part += " endInvocationInterlockNV(); \n"; - } - - m_part += " if (should_discard) discard; \n"; - - } - } -}; - -class ShaderFragmentRenderTarget : public ShaderPart -{ -public: - ShaderFragmentRenderTarget(const opengl::GLInfo & _glinfo) - { - if (config.generalEmulation.enableFragmentDepthWrite != 0) { - m_part = - " if (uRenderTarget != 0) { \n" - " if (uRenderTarget > 1) { \n" - " ivec2 coord = ivec2(gl_FragCoord.xy); \n" - " if (fragDepth >= texelFetch(uDepthTex, coord, 0).r) discard; \n" - " } \n" - " fragDepth = fragColor.r; \n" - " } \n" - " gl_FragDepth = fragDepth; \n" - ; - } - } -}; - -class ShaderFragmentMainEnd : public ShaderPart -{ -public: - ShaderFragmentMainEnd(const opengl::GLInfo & _glinfo) - { - if (_glinfo.isGLES2) { - m_part = - " gl_FragColor = fragColor; \n" - "} \n\n"; - } else { - m_part = - "} \n\n" - ; - } - } -}; - -class ShaderNoise : public ShaderPart -{ -public: - ShaderNoise(const opengl::GLInfo & _glinfo) - { - if (_glinfo.isGLES2) { - m_part = - "uniform sampler2D uTexNoise; \n" - "lowp float snoise() \n" - "{ \n" - " mediump vec2 texSize = vec2(640.0, 580.0); \n" - " mediump vec2 coord = gl_FragCoord.xy/uScreenScale/texSize; \n" - " return texture2D(uTexNoise, coord).r; \n" - "} \n" - ; - } else { - m_part = - "uniform sampler2D uTexNoise; \n" - "lowp float snoise() \n" - "{ \n" - " ivec2 coord = ivec2(gl_FragCoord.xy/uScreenScale); \n" - " return texelFetch(uTexNoise, coord, 0).r; \n" - "} \n" - ; - } - } -}; - -class ShaderDither : public ShaderPart -{ -public: - ShaderDither(const opengl::GLInfo & _glinfo) - { - if (_glinfo.isGLES2) - return; - - if (config.generalEmulation.enableDitheringQuantization != 0) { - m_part = - "void quantizeRGB(inout lowp vec3 _color) \n" - "{ \n" - " _color.rgb = round(_color.rgb * 32.0)/32.0; \n" - "} \n" - "void quantizeA(inout lowp float _alpha) \n" - "{ \n" - " _alpha = round(_alpha * 32.0)/32.0; \n" - "} \n" - ; - } else { - m_part = - "void quantizeRGB(inout lowp vec3 _color){}\n" - "void quantizeA(inout lowp float _alpha){}\n" - ; - } - - m_part += - "void colorDither(in lowp vec3 _noise, inout lowp vec3 _color)\n" - "{ \n" - " mediump vec3 threshold = 7.0 / 255.0 * (_noise - 0.5); \n" - " _color = clamp(_color + threshold,0.0,1.0); \n" - " quantizeRGB(_color); \n" - "} \n" - "void alphaDither(in lowp float _noise, inout lowp float _alpha)\n" - "{ \n" - " mediump float threshold = 7.0 / 255.0 * (_noise - 0.5); \n" - " _alpha = clamp(_alpha + threshold,0.0,1.0); \n" - " quantizeA(_alpha); \n" - "} \n" - "lowp vec3 snoiseRGB() \n" - "{ \n" - " mediump vec2 texSize = vec2(640.0, 580.0); \n" - ; - if (config.generalEmulation.enableHiresNoiseDithering != 0) - // multiplier for higher res noise effect - m_part += - " lowp float mult = 1.0 + step(2.0, uScreenScale.x); \n"; - else - m_part += - " lowp float mult = 1.0; \n"; - m_part += - " mediump vec2 coordR = mult * ((gl_FragCoord.xy)/uScreenScale/texSize);\n" - " mediump vec2 coordG = mult * ((gl_FragCoord.xy + vec2( 0.0, texSize.y / 2.0 ))/uScreenScale/texSize);\n" - " mediump vec2 coordB = mult * ((gl_FragCoord.xy + vec2( texSize.x / 2.0, 0.0))/uScreenScale/texSize);\n" - // Only red channel of noise texture contains noise. - " lowp float r = texture(uTexNoise,coordR).r; \n" - " lowp float g = texture(uTexNoise,coordG).r; \n" - " lowp float b = texture(uTexNoise,coordB).r; \n" - " \n" - " return vec3(r,g,b); \n" - "} \n" - "lowp float snoiseA() \n" - "{ \n" - " mediump vec2 texSize = vec2(640.0, 580.0); \n" - ; - if (config.generalEmulation.enableHiresNoiseDithering != 0) - // multiplier for higher res noise effect - m_part += - " lowp float mult = 1.0 + step(2.0, uScreenScale.x); \n"; - else - m_part += - " lowp float mult = 1.0; \n"; - m_part += - " \n" - " mediump vec2 coord = mult * ((gl_FragCoord.xy)/uScreenScale/texSize);\n" - " \n" - // Only red channel of noise texture contains noise. - " return texture(uTexNoise,coord).r; \n" - "} \n" - ; - } -}; - -class ShaderWriteDepth : public ShaderPart -{ -public: - ShaderWriteDepth(const opengl::GLInfo & _glinfo) - { - if (!_glinfo.isGLES2) { - if (config.generalEmulation.enableFragmentDepthWrite == 0 && - config.frameBufferEmulation.N64DepthCompare == Config::dcDisable) { - // Dummy write depth - m_part = - "highp float writeDepth() \n" - "{ \n" - " return 0.0; \n" - "} \n" - ; - } else { - if ((config.generalEmulation.hacks & hack_RE2) != 0) { - m_part = - "uniform lowp usampler2D uZlutImage;\n" - "highp float writeDepth() \n" - "{ \n" - ; - if (_glinfo.isGLESX) { - if (_glinfo.noPerspective) { - m_part += - " if (uClampMode == 1 && (vZCoord > 1.0)) discard; \n" - " highp float FragDepth = (uDepthSource != 0) ? uPrimDepth : \n" - " clamp((vZCoord - uPolygonOffset) * uDepthScale.s + uDepthScale.t, 0.0, 1.0); \n" - ; - } else if (config.generalEmulation.enableClipping != 0) { - m_part += - " highp float FragDepth = (uDepthSource != 0) ? uPrimDepth : \n" - " clamp(8.0 * (gl_FragCoord.z * 2.0 - 1.0) * uDepthScale.s + uDepthScale.t, 0.0, 1.0); \n" - ; - } else { - m_part += - " highp float FragDepth = (uDepthSource != 0) ? uPrimDepth : \n" - " clamp((gl_FragCoord.z * 2.0 - 1.0) * uDepthScale.s + uDepthScale.t, 0.0, 1.0); \n" - ; - } - } else { - m_part += - " highp float FragDepth = (uDepthSource != 0) ? uPrimDepth : \n" - " clamp((gl_FragCoord.z * 2.0 - 1.0) * uDepthScale.s + uDepthScale.t, 0.0, 1.0); \n" - ; - } - m_part += - " highp int iZ = FragDepth > 0.999 ? 262143 : int(floor(FragDepth * 262143.0)); \n" - " mediump int y0 = clamp(iZ/512, 0, 511); \n" - " mediump int x0 = iZ - 512*y0; \n" - " highp uint iN64z = texelFetch(uZlutImage,ivec2(x0,y0), 0).r; \n" - " return clamp(float(iN64z)/65532.0, 0.0, 1.0); \n" - "} \n" - ; - } else { - if (_glinfo.isGLESX) { - if (_glinfo.noPerspective) { - m_part = - "highp float writeDepth() \n" - "{ \n" - " if (uClampMode == 1 && (vZCoord > 1.0)) discard; \n" - " if (uDepthSource != 0) return uPrimDepth; \n" - " return clamp((vZCoord - uPolygonOffset) * uDepthScale.s + uDepthScale.t, 0.0, 1.0); \n" - "} \n" - ; - } else if (config.generalEmulation.enableClipping != 0) { - m_part = - "highp float writeDepth() \n" - "{ \n" - " if (uDepthSource != 0) return uPrimDepth; \n" - " return clamp(8.0 * (gl_FragCoord.z * 2.0 - 1.0) * uDepthScale.s + uDepthScale.t, 0.0, 1.0); \n" - "} \n" - ; - } else { - m_part = - "highp float writeDepth() \n" - "{ \n" - " if (uDepthSource != 0) return uPrimDepth; \n" - " return clamp((gl_FragCoord.z * 2.0 - 1.0) * uDepthScale.s + uDepthScale.t, 0.0, 1.0); \n" - "} \n" - ; - } - } else { - m_part = - "highp float writeDepth() \n" - "{ \n" - " if (uDepthSource != 0) return uPrimDepth; \n" - " return clamp((gl_FragCoord.z * 2.0 - 1.0) * uDepthScale.s + uDepthScale.t, 0.0, 1.0); \n" - "} \n" - ; - } - } - } - } - } -}; - -class ShaderMipmap : public ShaderPart -{ -public: - ShaderMipmap(const opengl::GLInfo & _glinfo) - { - if (_glinfo.isGLES2) { - static const std::string strReadTex0 = - "lowp vec4 TextureMipMap0(in sampler2D tex, in highp vec2 tcData[5]) \n" - "{ \n" - " mediump vec2 texSize = uTextureSize[0]; \n" - " lowp vec4 c00 = texture2D(tex, (tcData[0] + 0.5)/texSize); \n" - " lowp vec4 c01 = texture2D(tex, (tcData[1] + 0.5)/texSize); \n" - " lowp vec4 c10 = texture2D(tex, (tcData[2] + 0.5)/texSize); \n" - " lowp vec4 c11 = texture2D(tex, (tcData[3] + 0.5)/texSize); \n" - ; - static const std::string strReadTex1 = - "lowp vec4 TextureMipMap1(in sampler2D tex, in highp vec2 tcData[5], in lowp float lod) \n" - "{ \n" - // Fetch from texture atlas - // First 8 texels contain info about tile size and offset, 1 texel per tile - " mediump vec2 texSize = uTextureSize[1]; \n" - " mediump vec4 texWdthAndOff0 = 255.0 * texture2D(tex, vec2(0.5, 0.5)/texSize); \n" - " mediump vec4 texWdthAndOff = 255.0 * texture2D(tex, vec2(lod + 0.5, 0.5)/texSize); \n" - " mediump vec2 lod_scale = texWdthAndOff.ba / texWdthAndOff0.ba; \n" - " mediump float offset = texWdthAndOff.r + texWdthAndOff.g * 256.0; \n" - " mediump float width = texWdthAndOff.b; \n" - " mediump vec2 Coords00 = floor(tcData[0] * lod_scale); \n" - " mediump float offset00 = offset + width * Coords00.t + Coords00.s; \n" - " mediump float Y00 = floor(offset00 / mipmapTileWidth); \n" - " lowp vec4 c00 = texture2D(tex, (vec2(offset00 - mipmapTileWidth * Y00, Y00) + 0.5)/texSize); \n" - " mediump vec2 Coords01 = floor(tcData[1] * lod_scale); \n" - " mediump float offset01 = offset + width * Coords01.t + Coords01.s; \n" - " mediump float Y01 = floor(offset01 / mipmapTileWidth); \n" - " lowp vec4 c01 = texture2D(tex, (vec2(offset01 - mipmapTileWidth * Y01, Y01) + 0.5)/texSize); \n" - " mediump vec2 Coords10 = floor(tcData[2] * lod_scale); \n" - " mediump float offset10 = offset + width * Coords10.t + Coords10.s; \n" - " mediump float Y10 = floor(offset10 / mipmapTileWidth); \n" - " lowp vec4 c10 = texture2D(tex, (vec2(offset10 - mipmapTileWidth * Y10, Y10) + 0.5)/texSize); \n" - " mediump vec2 Coords11 = floor(tcData[3] * lod_scale); \n" - " mediump float offset11 = offset + width * Coords11.t + Coords11.s; \n" - " mediump float Y11 = floor(offset11 / mipmapTileWidth); \n" - " lowp vec4 c11 = texture2D(tex, (vec2(offset11 - mipmapTileWidth * Y11, Y11) + 0.5)/texSize); \n" - ; - static const std::string strBillinear3PointEndGles2 = - " lowp vec4 c0 = c00 + tcData[4].s*(c10-c00) + tcData[4].t*(c01-c00); \n" - " lowp vec4 c1 = c11 + (1.0-tcData[4].s)*(c01-c11) + (1.0-tcData[4].t)*(c10-c11); \n" - " lowp float bottomRightTri = step(1.0, tcData[4].s + tcData[4].t); \n" - " return c0 + bottomRightTri * (c1-c0); \n" - " return c00; \n" - "} \n" - ; - static const std::string strBillinearStandardEndGles2 = - " lowp vec4 c0 = c00 + tcData[4].s * (c10-c00); \n" - " lowp vec4 c1 = c01 + tcData[4].s * (c11-c01); \n" - " return c0 + tcData[4].t * (c1-c0); \n" - " return c00; \n" - "} \n" - ; - - if (config.texture.bilinearMode == BILINEAR_3POINT) { - m_part = strReadTex0; - m_part += strBillinear3PointEndGles2; - m_part += strReadTex1; - m_part += strBillinear3PointEndGles2; - } else { - m_part = strReadTex0; - m_part += strBillinearStandardEndGles2; - m_part += strReadTex1; - m_part += strBillinearStandardEndGles2; - } - - m_part += - "uniform lowp int uEnableLod; \n" - "uniform mediump float uMinLod; \n" - "uniform lowp int uMaxTile; \n" - "uniform lowp int uTextureDetail; \n" - " \n" - "mediump float mipmap(out lowp vec4 readtex0, out lowp vec4 readtex1) { \n" - ; - - if (config.generalEmulation.enableLOD == 0) { - m_part += - " mediump float lod = 1.0; \n" - ; - } else { - m_part += - " mediump vec2 dx = abs(dFdx(vLodTexCoord)) * uScreenScale; \n" - " mediump vec2 dy = abs(dFdy(vLodTexCoord)) * uScreenScale; \n" - " mediump float lod = max(max(dx.x, dx.y), max(dy.x, dy.y)); \n" - ; - } - m_part += - "#define MIN(x, y) y < x ? y : x \n" - "#define MAX(x, y) x < y ? y : x \n" - " lowp int lod_max_tile = uTextureDetail != 2 ? 7 : 6; \n" - " lowp int max_tile = MIN(lod_max_tile, uMaxTile); \n" - " mediump float min_lod = uTextureDetail != 0 ? uMinLod : 1.0; \n" - " mediump float max_lod = pow(2.0, float(max_tile)) - 1.0 / 32.0; \n" - " mediump float lod_clamp = min(max(lod, min_lod), max_lod); \n" - // Simulate clamp function, needed for GLES 2.0 and integer types - " mediump int lod_clamp_int = int(log2(lod_clamp)); \n" - " mediump int lod_clamp_max = MAX(lod_clamp_int, 0); \n" - " lowp int lod_tile = MIN(lod_clamp_max, max_tile); \n" - " lowp int tile0 = 0; \n" - " lowp int tile1 = 1; \n" - " if (uEnableLod != 0) { \n" - " if (lod_clamp < 1.0 && uTextureDetail == 0) { \n" - " tile0 = 0; \n" - " tile1 = 0; \n" - " } else if (lod_clamp >= 1.0 && uTextureDetail == 2) { \n" - " tile0 = lod_tile + 1; \n" - " tile1 = lod_tile + 2; \n" - " } else { \n" - " tile0 = lod_tile; \n" - " tile1 = lod_tile + 1; \n" - " } \n" - " } \n" - " mediump float lod_frac = lod_clamp / pow(2.0, float(lod_tile)); \n" - " if (uTextureDetail == 1 || lod_clamp >= 1.0) { \n" - " lod_frac = clamp(lod_frac - 1.0, -1.0, 1.0); \n" - " } \n" - " \n" - " if (tile0 == 0) \n" - " readtex0 = TextureMipMap0(uTex0, tcData0); \n" - " else if (uEnableLod == 0 || uMaxTile == 1) \n" - " readtex0 = TextureMipMap0(uTex1, tcData1); \n" - " else readtex0 = TextureMipMap1(uTex1, tcData1, float(tile0 - 1)); \n" - " if (tile1 == 0) \n" - " readtex1 = TextureMipMap0(uTex0, tcData0); \n" - " else if (uEnableLod == 0 || uMaxTile == 1) \n" - " readtex1 = TextureMipMap0(uTex1, tcData1); \n" - " else readtex1 = TextureMipMap1(uTex1, tcData1, float(tile1 - 1)); \n" - " return lod_frac; \n" - "} \n" - ; - } - else { - static const std::string strReadTex0 = - "#define READ_TEX0_MIPMAP(name, tex, tcData) \\\n" - "{ \\\n" - " lowp vec4 c00 = texelFetch(tex, ivec2(tcData[0]), 0); \\\n" - " lowp vec4 c01 = texelFetch(tex, ivec2(tcData[1]), 0); \\\n" - " lowp vec4 c10 = texelFetch(tex, ivec2(tcData[2]), 0); \\\n" - " lowp vec4 c11 = texelFetch(tex, ivec2(tcData[3]), 0); \\\n" - ; - static const std::string strReadTex1 = - "#define READ_TEX1_MIPMAP(name, tex, tcData, tile) \\\n" - "{ \\\n" - // Fetch from texture atlas - // First 8 texels contain info about tile size and offset, 1 texel per tile - " mediump vec4 texWdthAndOff0 = 255.0 * texelFetch(tex, ivec2(0, 0), 0); \\\n" - " mediump vec4 texWdthAndOff = 255.0 * texelFetch(tex, ivec2(int(tile), 0), 0); \\\n" - " mediump vec2 lod_scale = texWdthAndOff.ba / texWdthAndOff0.ba; \\\n" - " mediump int offset = int(texWdthAndOff.r) + int(texWdthAndOff.g) * 256; \\\n" - " mediump int width = int(texWdthAndOff.b); \\\n" - " mediump ivec2 iCoords00 = ivec2(tcData[0] * lod_scale); \\\n" - " mediump int offset00 = offset + width * iCoords00.t + iCoords00.s; \\\n" - " mediump int Y00 = offset00/mipmapTileWidth; \\\n" - " lowp vec4 c00 = texelFetch(tex, ivec2(offset00 - mipmapTileWidth * Y00, Y00), 0); \\\n" - " mediump ivec2 iCoords01 = ivec2(tcData[1] * lod_scale); \\\n" - " mediump int offset01 = offset + width * iCoords01.t + iCoords01.s; \\\n" - " mediump int Y01 = offset01/mipmapTileWidth; \\\n" - " lowp vec4 c01 = texelFetch(tex, ivec2(offset01 - mipmapTileWidth * Y01, Y01), 0); \\\n" - " mediump ivec2 iCoords10 = ivec2(tcData[2] * lod_scale); \\\n" - " mediump int offset10 = offset + width * iCoords10.t + iCoords10.s; \\\n" - " mediump int Y10 = offset10/mipmapTileWidth; \\\n" - " lowp vec4 c10 = texelFetch(tex, ivec2(offset10 - mipmapTileWidth * Y10, Y10), 0); \\\n" - " mediump ivec2 iCoords11 = ivec2(tcData[3] * lod_scale); \\\n" - " mediump int offset11 = offset + width * iCoords11.t + iCoords11.s; \\\n" - " mediump int Y11 = offset11/mipmapTileWidth; \\\n" - " lowp vec4 c11 = texelFetch(tex, ivec2(offset11 - mipmapTileWidth * Y11, Y11), 0); \\\n" - ; - static const std::string strBillinear3PointEnd = - " lowp vec4 c0 = c00 + tcData[4].s*(c10-c00) + tcData[4].t*(c01-c00); \\\n" - " lowp vec4 c1 = c11 + (1.0-tcData[4].s)*(c01-c11) + (1.0-tcData[4].t)*(c10-c11); \\\n" - " lowp float bottomRightTri = step(1.0, tcData[4].s + tcData[4].t); \\\n" - " name = c0 + bottomRightTri * (c1-c0); \\\n" - "} \n" - ; - static const std::string strBillinearStandardEnd = - " lowp vec4 c0 = c00 + tcData[4].s * (c10-c00); \\\n" - " lowp vec4 c1 = c01 + tcData[4].s * (c11-c01); \\\n" - " name = c0 + tcData[4].t * (c1-c0); \\\n" - "} \n" - ; - if (config.texture.bilinearMode == BILINEAR_3POINT) { - m_part = strReadTex0; - m_part += strBillinear3PointEnd; - m_part += strReadTex1; - m_part += strBillinear3PointEnd; - } else { - m_part = strReadTex0; - m_part += strBillinearStandardEnd; - m_part += strReadTex1; - m_part += strBillinearStandardEnd; - } - m_part += - "uniform lowp int uEnableLod; \n" - "uniform mediump float uMinLod; \n" - "uniform lowp int uMaxTile; \n" - "uniform lowp int uTextureDetail; \n" - " \n" - "mediump float mipmap(out lowp vec4 readtex0, out lowp vec4 readtex1) { \n" - ; - if (config.generalEmulation.enableLOD == 0) { - m_part += - " mediump float lod = 1.0; \n" - ; - } else { - m_part += - " mediump vec2 dx = abs(dFdx(vLodTexCoord)) * uScreenScale; \n" - " mediump vec2 dy = abs(dFdy(vLodTexCoord)) * uScreenScale; \n" - " mediump float lod = max(max(dx.x, dx.y), max(dy.x, dy.y)); \n" - ; - } - m_part += - " lowp int max_tile = min(uTextureDetail != 2 ? 7 : 6, uMaxTile); \n" - " mediump float min_lod = uTextureDetail != 0 ? uMinLod : 1.0; \n" - " mediump float max_lod = pow(2.0, float(max_tile)) - 1.0 / 32.0; \n" - " mediump float lod_clamp = min(max(lod, min_lod), max_lod); \n" - " lowp int lod_tile = clamp(int(log2(lod_clamp)), 0 , max_tile); \n" - " lowp int tile0 = 0; \n" - " lowp int tile1 = 1; \n" - " if (uEnableLod != 0) { \n" - " if (lod_clamp < 1.0 && uTextureDetail == 0) { \n" - " tile0 = 0; \n" - " tile1 = 0; \n" - " } else if (lod_clamp >= 1.0 && uTextureDetail == 2) { \n" - " tile0 = lod_tile + 1; \n" - " tile1 = lod_tile + 2; \n" - " } else { \n" - " tile0 = lod_tile; \n" - " tile1 = lod_tile + 1; \n" - " } \n" - " } \n" - " mediump float lod_frac = lod_clamp / pow(2.0, float(lod_tile)); \n" - " if (uTextureDetail == 1 || lod_clamp >= 1.0) { \n" - " lod_frac = clamp(lod_frac - 1.0, -1.0, 1.0); \n" - " } \n" - " \n" - " if(tile0 == 0) {READ_TEX0_MIPMAP(readtex0, uTex0, tcData0);} \n" - " else if (uEnableLod == 0 || uMaxTile == 1) {READ_TEX0_MIPMAP(readtex0, uTex1, tcData1);}\n" - " else {READ_TEX1_MIPMAP(readtex0, uTex1, tcData1, tile0 - 1);} \n" - " if(tile1 == 0) {READ_TEX0_MIPMAP(readtex1, uTex0, tcData0);} \n" - " else if (uEnableLod == 0 || uMaxTile == 1) {READ_TEX0_MIPMAP(readtex1, uTex1, tcData1);}\n" - " else {READ_TEX1_MIPMAP(readtex1, uTex1, tcData1, tile1 - 1);} \n" - " return lod_frac; \n" - "} \n" - ; - } - } -}; - -class ShaderCalcLight : public ShaderPart -{ -public: - ShaderCalcLight(const opengl::GLInfo & /*_glinfo*/) - { - m_part = - "uniform mediump vec3 uLightDirection[8]; \n" - "uniform lowp vec3 uLightColor[8]; \n" - "void calc_light(in lowp float fLights, in lowp vec3 input_color, out lowp vec3 output_color) {\n" - " output_color = input_color; \n" - " lowp int nLights = int(floor(fLights + 0.5)); \n" - " if (nLights == 0) \n" - " return; \n" - " output_color = uLightColor[nLights]; \n" - " mediump float intensity; \n" - " for (int i = 0; i < nLights; i++) { \n" - " intensity = max(dot(input_color, uLightDirection[i]), 0.0);\n" - " output_color += intensity*uLightColor[i]; \n" - " }; \n" - " output_color = clamp(output_color, 0.0, 1.0); \n" - "} \n" - ; - } -}; - -class ShaderReadtex : public ShaderPart -{ -public: - ShaderReadtex(const opengl::GLInfo & _glinfo) : m_glinfo(_glinfo) - { - } - - void write(std::stringstream & shader) const override - { - std::string shaderPart; - - if (m_glinfo.isGLES2) { - shaderPart += - "lowp vec4 TextureNearest(in sampler2D tex, in highp vec2 tcData[5]) \n" - "{ \n" - " mediump vec2 texSize; \n" - " if (nCurrentTile == 0) \n" - " texSize = uTextureSize[0]; \n" - " else \n" - " texSize = uTextureSize[1]; \n" - " return texture2D(tex, (tcData[0] + 0.5) / texSize); \n" - " } \n" - ; - if (g_textureConvert.useYUVCoversion()) - shaderPart += - "lowp vec4 YUV_Convert(in sampler2D tex, in highp vec2 tcData[5], in lowp int convert, in lowp int format, in lowp vec4 prev) \n" - "{ \n" - " lowp vec4 texColor; \n" - " if (convert != 0) texColor = prev; \n" - " else texColor = TextureNearest(tex, tcData); \n" - " mediump ivec4 icolor = ivec4(texColor*255.0); \n" - " if (format == 1) \n" - " icolor.rg -= 128; \n" - " mediump ivec4 iconvert; \n" - " iconvert.r = icolor.b + (uConvertParams[0]*icolor.g + 128)/256; \n" - " iconvert.g = icolor.b + (uConvertParams[1]*icolor.r + uConvertParams[2]*icolor.g + 128)/256; \n" - " iconvert.b = icolor.b + (uConvertParams[3]*icolor.r + 128)/256; \n" - " iconvert.a = icolor.b; \n" - " return vec4(iconvert)/255.0; \n" - " } \n" - ; - if (g_textureConvert.useTextureFiltering()) { - if (config.texture.bilinearMode == BILINEAR_3POINT) { - shaderPart += - // 3 point texture filtering. - // Original author: ArthurCarvalho - // GLSL implementation: twinaphex, mupen64plus-libretro project. - "lowp vec4 TextureFilter(in sampler2D tex, in highp vec2 tcData[5]) \n" - "{ \n" - " mediump vec2 texSize; \n" - " if (nCurrentTile == 0) \n" - " texSize = uTextureSize[0]; \n" - " else \n" - " texSize = uTextureSize[1]; \n" - " lowp float bottomRightTri = step(1.0, tcData[4].s + tcData[4].t); \n" - " lowp vec4 c00 = texture2D(tex, (tcData[0] + 0.5)/texSize); \n" - " lowp vec4 c01 = texture2D(tex, (tcData[1] + 0.5)/texSize); \n" - " lowp vec4 c10 = texture2D(tex, (tcData[2] + 0.5)/texSize); \n" - " lowp vec4 c11 = texture2D(tex, (tcData[3] + 0.5)/texSize); \n" - " lowp vec4 c0 = c00 + tcData[4].s*(c10-c00) + tcData[4].t*(c01-c00); \n" - " lowp vec4 c1 = c11 + (1.0-tcData[4].s)*(c01-c11) + (1.0-tcData[4].t)*(c10-c11); \n" - " return c0 + bottomRightTri * (c1-c0); \n" - " } \n" - ; - } else { - shaderPart += - // bilinear filtering. - "lowp vec4 TextureFilter(in sampler2D tex, in highp vec2 tcData[5]) \n" - "{ \n" - " mediump vec2 texSize; \n" - " if (nCurrentTile == 0) \n" - " texSize = uTextureSize[0]; \n" - " else \n" - " texSize = uTextureSize[1]; \n" - " lowp vec4 c00 = texture2D(tex, (tcData[0] + 0.5)/texSize); \n" - " lowp vec4 c01 = texture2D(tex, (tcData[1] + 0.5)/texSize); \n" - " lowp vec4 c10 = texture2D(tex, (tcData[2] + 0.5)/texSize); \n" - " lowp vec4 c11 = texture2D(tex, (tcData[3] + 0.5)/texSize); \n" - " lowp vec4 c0 = c00 + tcData[4].s * (c10-c00); \n" - " lowp vec4 c1 = c01 + tcData[4].s * (c11-c01); \n" - " return c0 + tcData[4].t * (c1-c0); \n" - " } \n" - ; - } - shaderPart += - "lowp vec4 readTex(in sampler2D tex, in highp vec2 tcData[5], in lowp int fbMonochrome, in lowp int fbFixedAlpha) \n" - "{ \n" - " lowp vec4 texColor; \n" - " if (uTextureFilterMode == 0) texColor = TextureNearest(tex, tcData); \n" - " else texColor = TextureFilter(tex, tcData); \n" - " if (fbMonochrome == 1) texColor = vec4(texColor.r); \n" - " else if (fbMonochrome == 2) \n" - " texColor.rgb = vec3(dot(vec3(0.2126, 0.7152, 0.0722), texColor.rgb)); \n" - " if (fbFixedAlpha == 1) texColor.a = 0.825; \n" - " return texColor; \n" - "} \n" - ; - } - } else { - if (config.video.multisampling > 0 && g_textureConvert.useTextureFiltering()) { - shaderPart = - "uniform lowp int uMSAASamples; \n" - "lowp vec4 sampleMS(in lowp sampler2DMS mstex, in mediump ivec2 ipos) \n" - "{ \n" - " lowp vec4 texel = vec4(0.0); \n" - " for (int i = 0; i < uMSAASamples; ++i) \n" - " texel += texelFetch(mstex, ipos, i); \n" - " return texel / float(uMSAASamples); \n" - "} \n" - " \n" - "lowp vec4 readTexMS(in lowp sampler2DMS mstex, in highp vec2 tcData[5], in lowp int fbMonochrome, in lowp int fbFixedAlpha) \n" - "{ \n" - " mediump ivec2 itexCoord; \n" - " if (fbMonochrome == 3) { \n" - " itexCoord = ivec2(gl_FragCoord.xy); \n" - " } else { \n" - " itexCoord = ivec2(tcData[0]); \n" - " } \n" - " lowp vec4 texColor = sampleMS(mstex, itexCoord); \n" - " if (fbMonochrome == 1) texColor = vec4(texColor.r); \n" - " else if (fbMonochrome == 2) \n" - " texColor.rgb = vec3(dot(vec3(0.2126, 0.7152, 0.0722), texColor.rgb)); \n" - " else if (fbMonochrome == 3) { \n" - " texColor.rgb = vec3(dot(vec3(0.2126, 0.7152, 0.0722), texColor.rgb)); \n" - " texColor.a = 0.0; \n" - " } \n" - " if (fbFixedAlpha == 1) texColor.a = 0.825; \n" - " return texColor; \n" - "} \n" - ; - } - } - - shader << shaderPart; - } - -private: - const opengl::GLInfo& m_glinfo; -}; - -class ShaderReadtexCopyMode : public ShaderPart -{ -public: - ShaderReadtexCopyMode(const opengl::GLInfo & _glinfo) - { - if (_glinfo.isGLES2) { - m_part = - "lowp vec4 TextureNearest(in sampler2D tex, in highp vec2 tcData[5]) \n" - "{ \n" - " mediump vec2 texSize; \n" - " if (nCurrentTile == 0) \n" - " texSize = uTextureSize[0]; \n" - " else \n" - " texSize = uTextureSize[1]; \n" - " return texture2D(tex, (tcData[0] + 0.5) / texSize); \n" - " } \n" - "lowp vec4 readTex(in sampler2D tex, in highp vec2 tcData[5], in lowp int fbMonochrome, in lowp int fbFixedAlpha) \n" - "{ \n" - " lowp vec4 texColor = TextureNearest(tex, tcData); \n" - " if (fbMonochrome == 1) texColor = vec4(texColor.r); \n" - " else if (fbMonochrome == 2) \n" - " texColor.rgb = vec3(dot(vec3(0.2126, 0.7152, 0.0722), texColor.rgb)); \n" - " if (fbFixedAlpha == 1) texColor.a = 0.825; \n" - " return texColor; \n" - "} \n" - ; - } else { - if (config.video.multisampling > 0) { - m_part = - "uniform lowp int uMSAASamples; \n" - "lowp vec4 sampleMS(in lowp sampler2DMS mstex, in mediump ivec2 ipos) \n" - "{ \n" - " lowp vec4 texel = vec4(0.0); \n" - " for (int i = 0; i < uMSAASamples; ++i) \n" - " texel += texelFetch(mstex, ipos, i); \n" - " return texel / float(uMSAASamples); \n" - "} \n" - " \n" - "lowp vec4 readTexMS(in lowp sampler2DMS mstex, in highp vec2 tcData[5], in lowp int fbMonochrome, in lowp int fbFixedAlpha) \n" - "{ \n" - " mediump ivec2 itexCoord; \n" - " if (fbMonochrome == 3) { \n" - " itexCoord = ivec2(gl_FragCoord.xy); \n" - " } else { \n" - " itexCoord = ivec2(tcData[0]); \n" - " } \n" - " lowp vec4 texColor = sampleMS(mstex, itexCoord); \n" - " if (fbMonochrome == 1) texColor = vec4(texColor.r); \n" - " else if (fbMonochrome == 2) \n" - " texColor.rgb = vec3(dot(vec3(0.2126, 0.7152, 0.0722), texColor.rgb)); \n" - " else if (fbMonochrome == 3) { \n" - " texColor.rgb = vec3(dot(vec3(0.2126, 0.7152, 0.0722), texColor.rgb)); \n" - " texColor.a = 0.0; \n" - " } \n" - " if (fbFixedAlpha == 1) texColor.a = 0.825; \n" - " return texColor; \n" - "} \n" - ; - } - } - } -}; - -class ShaderN64DepthCompare : public ShaderPart -{ -public: - ShaderN64DepthCompare(const opengl::GLInfo & _glinfo) - { - if (config.frameBufferEmulation.N64DepthCompare != Config::dcDisable) { - m_part = - "uniform lowp int uEnableDepth; \n" - "uniform lowp int uDepthMode; \n" - "uniform lowp int uEnableDepthUpdate; \n" - "uniform mediump float uDeltaZ; \n" - "bool depth_compare(highp float curZ) \n" - "{ \n" - " if (uEnableDepth == 0) return true; \n" - ; - if (_glinfo.imageTextures && !_glinfo.n64DepthWithFbFetch) { - m_part += - " ivec2 coord = ivec2(gl_FragCoord.xy); \n" - " highp vec4 depthZ = imageLoad(uDepthImageZ,coord); \n" - " highp vec4 depthDeltaZ = imageLoad(uDepthImageDeltaZ,coord);\n" - ; - } - m_part += - " highp float bufZ = depthZ.r; \n" - " highp float dz, dzMin; \n" - " if (uDepthSource == 1) { \n" - " dzMin = dz = uDeltaZ; \n" - " } else { \n" - " dz = 4.0*fwidth(curZ); \n" - " dzMin = min(dz, depthDeltaZ.r); \n" - " } \n" - " bool bInfront = curZ < bufZ; \n" - " bool bFarther = (curZ + dzMin) >= bufZ; \n" - " bool bNearer = (curZ - dzMin) <= bufZ; \n" - " bool bMax = bufZ == 1.0; \n" - " bool bRes = false; \n" - " switch (uDepthMode) { \n" - " case 1: \n" - " bRes = bMax || bNearer; \n" - " break; \n" - " case 0: \n" - " case 2: \n" - " bRes = bMax || bInfront; \n" - " break; \n" - " case 3: \n" - " bRes = bFarther && bNearer && !bMax; \n" - " break; \n" - " } \n" - " bRes = bRes || (uEnableDepthCompare == 0); \n" - " if (uEnableDepthUpdate != 0 && bRes) { \n" - ; - if (_glinfo.n64DepthWithFbFetch) { - m_part += - " depthZ.r = curZ; \n" - " depthDeltaZ.r = dz; \n" - ; - } else if (_glinfo.imageTextures) { - m_part += - " highp vec4 depthOutZ = vec4(curZ, 1.0, 1.0, 1.0); \n" - " highp vec4 depthOutDeltaZ = vec4(dz, 1.0, 1.0, 1.0); \n" - " imageStore(uDepthImageZ, coord, depthOutZ); \n" - " imageStore(uDepthImageDeltaZ, coord, depthOutDeltaZ); \n" - ; - } - - m_part += - " } \n" - " return bRes; \n" - "} \n" - ; - } - } -}; - -class ShaderN64DepthRender : public ShaderPart -{ -public: - ShaderN64DepthRender(const opengl::GLInfo & _glinfo) - { - if (config.frameBufferEmulation.N64DepthCompare != Config::dcDisable) { - m_part = - "bool depth_render(highp float Z, highp float curZ) \n" - "{ \n" - " ivec2 coord = ivec2(gl_FragCoord.xy); \n" - " if (uEnableDepthCompare != 0) { \n" - ; - if (_glinfo.imageTextures && !_glinfo.n64DepthWithFbFetch) { - m_part += - " highp vec4 depthZ = imageLoad(uDepthImageZ,coord); \n" - ; - } - m_part += - " highp float bufZ = depthZ.r; \n" - " if (curZ >= bufZ) return false; \n" - " } \n" - ; - if (_glinfo.n64DepthWithFbFetch) { - m_part += - " depthZ.r = Z; \n" - " depthDeltaZ.r = 0.0; \n" - ; - } else if (_glinfo.imageTextures) { - m_part += - " highp vec4 depthOutZ = vec4(Z, 1.0, 1.0, 1.0); \n" - " highp vec4 depthOutDeltaZ = vec4(0.0, 1.0, 1.0, 1.0);\n" - " imageStore(uDepthImageZ,coord, depthOutZ); \n" - " imageStore(uDepthImageDeltaZ,coord, depthOutDeltaZ); \n" - ; - } - - m_part += - " return true; \n" - "} \n" - ; - } - } -}; - - -class ShaderFragmentCorrectTexCoords : public ShaderPart { -public: - ShaderFragmentCorrectTexCoords() { - m_part += - " highp vec2 mTexCoord0 = vTexCoord0 + vec2(0.0001); \n" - " highp vec2 mTexCoord1 = vTexCoord1 + vec2(0.0001); \n" - " mTexCoord0 += uTexCoordOffset[0]; \n" - " mTexCoord1 += uTexCoordOffset[1]; \n" - " if (uUseTexCoordBounds != 0) { \n" - " mTexCoord0 = clamp(mTexCoord0, uTexCoordBounds0.xy, uTexCoordBounds0.zw); \n" - " mTexCoord1 = clamp(mTexCoord1, uTexCoordBounds1.xy, uTexCoordBounds1.zw); \n" - " } \n" - ; - } -}; - - -class ShaderTextureEngine : public ShaderPart -{ -public: - ShaderTextureEngine(const opengl::GLInfo _glinfo) { - m_part = - "highp vec2 clampWrapMirror(in highp vec2 vTexCoord, in highp vec2 vWrap, \n" - " in highp vec2 vClamp, in lowp vec2 vWrapEn, in lowp vec2 vClampEn, in lowp vec2 vMirrorEn) \n" - "{ \n" - " highp vec2 texCoord = vTexCoord; \n" - " highp vec2 clampedCoord = clamp(texCoord, vec2(0.0), vClamp); \n" - " texCoord += vClampEn*(clampedCoord-texCoord); \n" - " lowp vec2 needMirror = step(vWrap, mod(texCoord, 2.0*vWrap)); \n" - " highp vec2 invertedCoord = mod(-texCoord-vec2(1.0), vWrap); \n" - " texCoord += vMirrorEn*needMirror*(invertedCoord-texCoord); \n" - " highp vec2 wrappedCoord = mod(texCoord,vWrap); \n" - " texCoord += vWrapEn*(wrappedCoord-texCoord); \n" - " return texCoord; \n" - "} \n" - - "highp vec2 wrap2D(in highp vec2 tc, in highp vec2 size) \n" - "{ \n" - " highp float divs = floor(tc.s / size.s); \n" - " highp float divt = floor((tc.t + divs) / size.t); \n" - " return vec2(tc.s - divs * size.s, tc.t + divs - divt*size.t); \n" - "} \n" - - "void textureEngine0(in highp vec2 texCoord, out highp vec2 tcData[5]) \n" - "{ \n" - " highp vec2 tileCoord = (WRAP(texCoord * uShiftScale[0] - uTexOffset[0], -1024.0, 1024.0));\n" - " tileCoord = (tileCoord + uBilinearOffset) * uHDRatio[0] - uBilinearOffset; \n" - " mediump vec2 intPart = floor(tileCoord); \n" - " highp vec2 tc00 = clampWrapMirror(intPart, uTexWrap[0], uTexClamp[0], uTexWrapEn[0], uTexClampEn[0], uTexMirrorEn[0]); \n" - " highp vec2 tc11 = clampWrapMirror(intPart + vec2(1.0,1.0), uTexWrap[0], uTexClamp[0], uTexWrapEn[0], uTexClampEn[0], uTexMirrorEn[0]); \n" - " tcData[0] = wrap2D(tc00, uTexSize[0]) + uCacheOffset[0]; \n" - " tcData[3] = wrap2D(tc11, uTexSize[0]) + uCacheOffset[0]; \n" - " tcData[1] = vec2(tcData[0].s, tcData[3].t); \n" - " tcData[2] = vec2(tcData[3].s, tcData[0].t); \n" - " tcData[4] = tileCoord - intPart; \n" - "} \n" - - "void textureEngine1(in highp vec2 texCoord, out highp vec2 tcData[5]) \n" - "{ \n" - " highp vec2 tileCoord = (WRAP(texCoord * uShiftScale[1] - uTexOffset[1], -1024.0, 1024.0)); \n" - " tileCoord = (tileCoord + uBilinearOffset) * uHDRatio[1] - uBilinearOffset; \n" - " mediump vec2 intPart = floor(tileCoord); \n" - " highp vec2 tc00 = clampWrapMirror(intPart, uTexWrap[1], uTexClamp[1], uTexWrapEn[1], uTexClampEn[1], uTexMirrorEn[1]); \n" - " highp vec2 tc11 = clampWrapMirror(intPart + vec2(1.0,1.0), uTexWrap[1], uTexClamp[1], uTexWrapEn[1], uTexClampEn[1], uTexMirrorEn[1]); \n" - " tcData[0] = wrap2D(tc00, uTexSize[1]) + uCacheOffset[1]; \n" - " tcData[3] = wrap2D(tc11, uTexSize[1]) + uCacheOffset[1]; \n" - " tcData[1] = vec2(tcData[0].s, tcData[3].t); \n" - " tcData[2] = vec2(tcData[3].s, tcData[0].t); \n" - " tcData[4] = tileCoord - intPart; \n" - "} \n" - - ; - } -}; - - -class ShaderFragmentTextureEngineTex0 : public ShaderPart { -public: - ShaderFragmentTextureEngineTex0(const opengl::GLInfo _glinfo) - { - m_part = - "textureEngine0(mTexCoord0, tcData0); \n" - ; - } -}; - -class ShaderFragmentTextureEngineTex1 : public ShaderPart { -public: - ShaderFragmentTextureEngineTex1(const opengl::GLInfo _glinfo) - { - m_part = - "textureEngine1(mTexCoord1, tcData1); \n" - ; - } -}; - -class ShaderCoverage : public ShaderPart { -public: - ShaderCoverage() { - m_part = - "const highp vec2 bias[8] = vec2[8] (vec2(-0.5,-0.5), vec2(0.0, -0.5), vec2(-0.25,-0.25), vec2(0.25, -0.25), \n" - " vec2(-0.5, 0.0), vec2(0.0,0.0), vec2(-0.25,0.25), vec2(0.25,0.25)); \n" - "highp vec4 dBCdx = dFdx(vBaryCoords); \n" - "highp vec4 dBCdy = dFdy(vBaryCoords); \n" - "cvg = 0.0; \n" - "for (int i = 0; i<8; i++) { \n" - " highp vec2 currentBias = bias[i]; \n" - " highp vec4 baryCoordsBiased = vBaryCoords + dBCdx*currentBias.x + dBCdy * currentBias.y; \n" - " lowp vec4 inside = step(0.0, baryCoordsBiased); \n" - " cvg += 0.125 * inside[0] * inside[1] * inside[2] * inside[3]; \n" - "} \n" - ; - } -}; - - -/*---------------ShaderPartsEnd-------------*/ - static bool needClampColor() { - return g_cycleType <= G_CYC_2CYCLE; + return CombinerProgramBuilder::s_cycleType <= G_CYC_2CYCLE; } static bool combinedColorC(const gDPCombine & _combine) { - if (g_cycleType != G_CYC_2CYCLE) + if (CombinerProgramBuilder::s_cycleType != G_CYC_2CYCLE) return false; return _combine.mRGB1 == G_CCMUX_COMBINED; } static bool combinedAlphaC(const gDPCombine & _combine) { - if (g_cycleType != G_CYC_2CYCLE) + if (CombinerProgramBuilder::s_cycleType != G_CYC_2CYCLE) return false; return _combine.mA1 == G_ACMUX_COMBINED; } static bool combinedColorABD(const gDPCombine & _combine) { - if (g_cycleType != G_CYC_2CYCLE) + if (CombinerProgramBuilder::s_cycleType != G_CYC_2CYCLE) return false; if (_combine.aRGB1 == G_CCMUX_COMBINED) return true; @@ -2780,7 +234,7 @@ bool combinedColorABD(const gDPCombine & _combine) { static bool combinedAlphaABD(const gDPCombine & _combine) { - if (g_cycleType != G_CYC_2CYCLE) + if (CombinerProgramBuilder::s_cycleType != G_CYC_2CYCLE) return false; if (_combine.aA1 == G_ACMUX_COMBINED) return true; @@ -2796,7 +250,7 @@ CombinerInputs CombinerProgramBuilder::compileCombiner(const CombinerKey & _key, std::stringstream ssShader; - if (g_cycleType != G_CYC_2CYCLE) { + if (CombinerProgramBuilder::s_cycleType != G_CYC_2CYCLE) { _correctFirstStageParams(_alpha.stage[0]); _correctFirstStageParams(_color.stage[0]); } else { @@ -2807,22 +261,22 @@ CombinerInputs CombinerProgramBuilder::compileCombiner(const CombinerKey & _key, CombinerInputs inputs = _compileCombiner(_alpha.stage[0], AlphaInput, ssShader); // Simulate N64 color sign-extend. if (combinedAlphaC(combine)) - m_signExtendAlphaC->write(ssShader); + _writeSignExtendAlphaC(ssShader); else if (combinedAlphaABD(combine)) - m_signExtendAlphaABD->write(ssShader); + _writeSignExtendAlphaABD(ssShader); - if (g_cycleType < G_CYC_FILL) - m_alphaTest->write(ssShader); + if (CombinerProgramBuilder::s_cycleType < G_CYC_FILL) + _writeAlphaTest(ssShader); ssShader << " color1 = "; inputs += _compileCombiner(_color.stage[0], ColorInput, ssShader); // Simulate N64 color sign-extend. if (combinedColorC(combine)) - m_signExtendColorC->write(ssShader); + _writeSignExtendColorC(ssShader); else if (combinedColorABD(combine)) - m_signExtendColorABD->write(ssShader); + _writeSignExtendColorABD(ssShader); - if (g_cycleType == G_CYC_2CYCLE) { + if (CombinerProgramBuilder::s_cycleType == G_CYC_2CYCLE) { ssShader << " combined_color = vec4(color1, alpha1);" << std::endl; if (_alpha.numStages == 2) { @@ -2846,19 +300,19 @@ CombinerInputs CombinerProgramBuilder::compileCombiner(const CombinerKey & _key, ssShader << " lowp vec4 cmbRes = vec4(color2, alpha2);" << std::endl; } else { - if (g_cycleType < G_CYC_FILL) + if (CombinerProgramBuilder::s_cycleType < G_CYC_FILL) ssShader << " if (uCvgXAlpha != 0 && alpha1 < 0.125) discard;" << std::endl; ssShader << " lowp vec4 cmbRes = vec4(color1, alpha1);" << std::endl; } // Simulate N64 color clamp. if (needClampColor()) - m_clamp->write(ssShader); + _writeClamp(ssShader); else ssShader << " lowp vec4 clampedColor = clamp(cmbRes, 0.0, 1.0);" << std::endl; - if (g_cycleType <= G_CYC_2CYCLE) { - m_callDither->write(ssShader); + if (CombinerProgramBuilder::s_cycleType <= G_CYC_2CYCLE) { + _writeCallDither(ssShader); ssShader << "if (uCvgXAlpha != 0) cvg *= clampedColor.a;" << std::endl; ssShader << "if (uAlphaCvgSel != 0) clampedColor.a = cvg; " << std::endl; @@ -2866,18 +320,18 @@ CombinerInputs CombinerProgramBuilder::compileCombiner(const CombinerKey & _key, if (config.generalEmulation.enableLegacyBlending == 0) { - if (g_cycleType <= G_CYC_2CYCLE) { - m_blender1->write(ssShader); - if (g_cycleType == G_CYC_2CYCLE) - m_blender2->write(ssShader); - m_blenderAlpha->write(ssShader); + if (CombinerProgramBuilder::s_cycleType <= G_CYC_2CYCLE) { + _writeBlender1(ssShader); + if (CombinerProgramBuilder::s_cycleType == G_CYC_2CYCLE) + _writeBlender2(ssShader); + _writeBlenderAlpha(ssShader); } else ssShader << " fragColor = clampedColor;" << std::endl; } else { ssShader << " fragColor = clampedColor;" << std::endl; - m_legacyBlender->write(ssShader); + _writeLegacyBlender(ssShader); } @@ -2892,8 +346,8 @@ graphics::CombinerProgram * CombinerProgramBuilder::buildCombinerProgram(Combine Combiner & _alpha, const CombinerKey & _key) { - g_cycleType = _key.getCycleType(); - g_textureConvert.setMode(_key.getBilerp()); + CombinerProgramBuilder::s_cycleType = _key.getCycleType(); + CombinerProgramBuilder::s_textureConvert.setMode(_key.getBilerp()); std::string strCombiner; CombinerInputs combinerInputs(compileCombiner(_key, _color, _alpha, strCombiner)); @@ -2911,83 +365,83 @@ graphics::CombinerProgram * CombinerProgramBuilder::buildCombinerProgram(Combine std::stringstream ssShader; /* Write headers */ - m_fragmentHeader->write(ssShader); + _writeFragmentHeader(ssShader); if (bUseTextures) { - m_fragmentGlobalVariablesTex->write(ssShader); + _writeFragmentGlobalVariablesTex(ssShader); - if (g_cycleType == G_CYC_2CYCLE && config.generalEmulation.enableLegacyBlending == 0) + if (CombinerProgramBuilder::s_cycleType == G_CYC_2CYCLE && config.generalEmulation.enableLegacyBlending == 0) ssShader << "uniform lowp ivec4 uBlendMux2;" << std::endl << "uniform lowp int uForceBlendCycle2;" << std::endl; - if (g_cycleType <= G_CYC_2CYCLE) - m_fragmentHeaderDither->write(ssShader); - m_fragmentHeaderNoise->write(ssShader); - m_fragmentHeaderWriteDepth->write(ssShader); - m_fragmentHeaderDepthCompare->write(ssShader); - m_fragmentHeaderReadMSTex->write(ssShader); - m_fragmentHeaderTextureEngine->write(ssShader); + if (CombinerProgramBuilder::s_cycleType <= G_CYC_2CYCLE) + _writeFragmentHeaderDither(ssShader); + _writeFragmentHeaderNoise(ssShader); + _writeFragmentHeaderWriteDepth(ssShader); + _writeFragmentHeaderDepthCompare(ssShader); + _writeFragmentHeaderReadMSTex(ssShader); + _writeFragmentHeaderClampWrapMirrorEngine(ssShader); if (bUseLod) - m_fragmentHeaderMipMap->write(ssShader); - else if (g_cycleType < G_CYC_COPY) - m_fragmentHeaderReadTex->write(ssShader); + _writeFragmentHeaderMipMap(ssShader); + else if (CombinerProgramBuilder::s_cycleType < G_CYC_COPY) + _writeFragmentHeaderReadTex(ssShader); else - m_fragmentHeaderReadTexCopyMode->write(ssShader); + _writeFragmentHeaderReadTexCopyMode(ssShader); } else { - m_fragmentGlobalVariablesNotex->write(ssShader); + _writeFragmentGlobalVariablesNotex(ssShader); - if (g_cycleType == G_CYC_2CYCLE && config.generalEmulation.enableLegacyBlending == 0) + if (CombinerProgramBuilder::s_cycleType == G_CYC_2CYCLE && config.generalEmulation.enableLegacyBlending == 0) ssShader << "uniform lowp ivec4 uBlendMux2;" << std::endl << "uniform lowp int uForceBlendCycle2;" << std::endl; - if (g_cycleType <= G_CYC_2CYCLE) - m_fragmentHeaderDither->write(ssShader); - m_fragmentHeaderNoise->write(ssShader); - m_fragmentHeaderWriteDepth->write(ssShader); - m_fragmentHeaderDepthCompare->write(ssShader); + if (CombinerProgramBuilder::s_cycleType <= G_CYC_2CYCLE) + _writeFragmentHeaderDither(ssShader); + _writeFragmentHeaderNoise(ssShader); + _writeFragmentHeaderWriteDepth(ssShader); + _writeFragmentHeaderDepthCompare(ssShader); } if (bUseHWLight) - m_fragmentHeaderCalcLight->write(ssShader); + _writeFragmentHeaderCalcLight(ssShader); /* Write body */ - if (g_cycleType == G_CYC_2CYCLE) - m_fragmentMain2Cycle->write(ssShader); + if (CombinerProgramBuilder::s_cycleType == G_CYC_2CYCLE) + _writeFragmentMain2Cycle(ssShader); else - m_fragmentMain->write(ssShader); + _writeFragmentMain(ssShader); - if (g_cycleType <= G_CYC_2CYCLE) - m_fragmentBlendMux->write(ssShader); + if (CombinerProgramBuilder::s_cycleType <= G_CYC_2CYCLE) + _writeFragmentBlendMux(ssShader); - if (g_cycleType <= G_CYC_2CYCLE && m_useCoverage) - m_shaderCoverage->write(ssShader); + if (CombinerProgramBuilder::s_cycleType <= G_CYC_2CYCLE && m_useCoverage) + _writeShaderCoverage(ssShader); else ssShader << "cvg = 1.0; \n" << std::endl; if (bUseTextures) { - m_fragmentCorrectTexCoords->write(ssShader); + _writeFragmentCorrectTexCoords(ssShader); if (combinerInputs.usesTile(0)) { - m_fragmentTextureEngineTex0->write(ssShader); + _writeFragmentClampWrapMirrorEngineTex0(ssShader); } if (combinerInputs.usesTile(1)) { - m_fragmentTextureEngineTex1->write(ssShader); + _writeFragmentClampWrapMirrorEngineTex1(ssShader); } if (bUseLod) { - m_fragmentReadTexMipmap->write(ssShader); + _writeFragmentReadTexMipmap(ssShader); } else { - if (g_cycleType < G_CYC_COPY) { + if (CombinerProgramBuilder::s_cycleType < G_CYC_COPY) { if (combinerInputs.usesTile(0)) - m_fragmentReadTex0->write(ssShader); + _writeFragmentReadTex0(ssShader); else ssShader << " lowp vec4 readtex0;" << std::endl; if (combinerInputs.usesTile(1)) - m_fragmentReadTex1->write(ssShader); + _writeFragmentReadTex1(ssShader); } else - m_fragmentReadTexCopyMode->write(ssShader); + _writeFragmentReadTexCopyMode(ssShader); } } @@ -3000,39 +454,39 @@ graphics::CombinerProgram * CombinerProgramBuilder::buildCombinerProgram(Combine ssShader << strCombiner << std::endl; if (config.frameBufferEmulation.N64DepthCompare != Config::dcDisable) - m_fragmentCallN64Depth->write(ssShader); + _writeFragmentCallN64Depth(ssShader); else - m_fragmentRenderTarget->write(ssShader); + _writeFragmentRenderTarget(ssShader); // End of Main() function - m_shaderFragmentMainEnd->write(ssShader); + _writeShaderFragmentMainEnd(ssShader); /* Write other functions */ if (bUseHWLight) - m_shaderCalcLight->write(ssShader); + _writeShaderCalcLight(ssShader); if (bUseTextures) { - m_shaderTextureEngine->write(ssShader); + _writeShaderClampWrapMirrorEngine(ssShader); if (bUseLod) - m_shaderMipmap->write(ssShader); + _writeShaderMipmap(ssShader); else { - if (g_cycleType < G_CYC_COPY) - m_shaderReadtex->write(ssShader); + if (CombinerProgramBuilder::s_cycleType < G_CYC_COPY) + _writeShaderReadtex(ssShader); else - m_shaderReadtexCopyMode->write(ssShader); + _writeShaderReadtexCopyMode(ssShader); } } - m_shaderNoise->write(ssShader); + _writeShaderNoise(ssShader); - if (g_cycleType <= G_CYC_2CYCLE) - m_shaderDither->write(ssShader); + if (CombinerProgramBuilder::s_cycleType <= G_CYC_2CYCLE) + _writeShaderDither(ssShader); - m_shaderWriteDepth->write(ssShader); + _writeShaderWriteDepth(ssShader); - m_shaderN64DepthCompare->write(ssShader); + _writeShaderN64DepthCompare(ssShader); - m_shaderN64DepthRender->write(ssShader); + _writeShaderN64DepthRender(ssShader); const std::string strFragmentShader(ssShader.str()); @@ -3043,14 +497,14 @@ graphics::CombinerProgram * CombinerProgramBuilder::buildCombinerProgram(Combine glShaderSource(fragmentShader, 1, &strShaderData, nullptr); glCompileShader(fragmentShader); if (!Utils::checkShaderCompileStatus(fragmentShader)) - Utils::logErrorShader(GL_FRAGMENT_SHADER, strFragmentShader); + Utils::logErrorShader(GL_FRAGMENT_SHADER, strFragmentShader); GLuint program = glCreateProgram(); Utils::locateAttributes(program, bIsRect, bUseTextures); if (bIsRect) - glAttachShader(program, bUseTextures ? m_vertexShaderTexturedRect : m_vertexShaderRect); + glAttachShader(program, bUseTextures ? _getVertexShaderTexturedRect() : _getVertexShaderRect()); else - glAttachShader(program, bUseTextures ? m_vertexShaderTexturedTriangle : m_vertexShaderTriangle); + glAttachShader(program, bUseTextures ? _getVertexShaderTexturedTriangle() : _getVertexShaderTriangle()); glAttachShader(program, fragmentShader); if (CombinerInfo::get().isShaderCacheSupported()) { if (IS_GL_FUNCTION_VALID(ProgramParameteri)) @@ -3066,114 +520,16 @@ graphics::CombinerProgram * CombinerProgramBuilder::buildCombinerProgram(Combine return new CombinerProgramImpl(_key, program, m_useProgram, combinerInputs, std::move(uniforms)); } -const ShaderPart * CombinerProgramBuilder::getVertexShaderHeader() const -{ - return m_vertexHeader.get(); -} - -const ShaderPart * CombinerProgramBuilder::getFragmentShaderHeader() const -{ - return m_fragmentHeader.get(); -} - -const ShaderPart * CombinerProgramBuilder::getFragmentShaderEnd() const -{ - return m_shaderFragmentMainEnd.get(); -} - -static -GLuint _createVertexShader(ShaderPart * _header, ShaderPart * _body, ShaderPart * _footer) -{ - std::stringstream ssShader; - _header->write(ssShader); - _body->write(ssShader); - _footer->write(ssShader); - const std::string strShader(ssShader.str()); - const GLchar * strShaderData = strShader.data(); - - GLuint shader_object = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(shader_object, 1, &strShaderData, nullptr); - glCompileShader(shader_object); - if (!Utils::checkShaderCompileStatus(shader_object)) - Utils::logErrorShader(GL_VERTEX_SHADER, strShaderData); - return shader_object; -} - -CombinerProgramBuilder::CombinerProgramBuilder(const opengl::GLInfo & _glinfo, opengl::CachedUseProgram * _useProgram) -: m_blender1(new ShaderBlender1(_glinfo)) -, m_blender2(new ShaderBlender2(_glinfo)) -, m_blenderAlpha (new ShaderBlenderAlpha(_glinfo)) -, m_legacyBlender(new ShaderLegacyBlender) -, m_clamp(new ShaderClamp) -, m_signExtendColorC(new ShaderSignExtendColorC) -, m_signExtendAlphaC(new ShaderSignExtendAlphaC) -, m_signExtendColorABD(new ShaderSignExtendColorABD) -, m_signExtendAlphaABD(new ShaderSignExtendAlphaABD) -, m_alphaTest(new ShaderAlphaTest) -, m_callDither(new ShaderDithering(_glinfo)) -, m_vertexHeader(new VertexShaderHeader(_glinfo)) -, m_vertexEnd(new VertexShaderEnd(_glinfo)) -, m_vertexRect(new VertexShaderRect(_glinfo)) -, m_vertexTexturedRect(new VertexShaderTexturedRect(_glinfo)) -, m_vertexTriangle(new VertexShaderTriangle(_glinfo)) -, m_vertexTexturedTriangle(new VertexShaderTexturedTriangle(_glinfo)) -, m_fragmentHeader(new FragmentShaderHeader(_glinfo)) -, m_fragmentGlobalVariablesTex(new ShaderFragmentGlobalVariablesTex(_glinfo)) -, m_fragmentGlobalVariablesNotex(new ShaderFragmentGlobalVariablesNotex(_glinfo)) -, m_fragmentHeaderNoise(new ShaderFragmentHeaderNoise(_glinfo)) -, m_fragmentHeaderWriteDepth(new ShaderFragmentHeaderWriteDepth(_glinfo)) -, m_fragmentHeaderCalcLight(new ShaderFragmentHeaderCalcLight(_glinfo)) -, m_fragmentHeaderMipMap(new ShaderFragmentHeaderMipMap(_glinfo)) -, m_fragmentHeaderTextureEngine(new ShaderFragmentHeaderTextureEngine(_glinfo)) -, m_fragmentHeaderReadMSTex(new ShaderFragmentHeaderReadMSTex(_glinfo)) -, m_fragmentHeaderDither(new ShaderFragmentHeaderDither(_glinfo)) -, m_fragmentHeaderDepthCompare(new ShaderFragmentHeaderDepthCompare(_glinfo)) -, m_fragmentHeaderReadTex(new ShaderFragmentHeaderReadTex(_glinfo)) -, m_fragmentHeaderReadTexCopyMode(new ShaderFragmentHeaderReadTexCopyMode(_glinfo)) -, m_fragmentMain(new ShaderFragmentMain(_glinfo)) -, m_fragmentMain2Cycle(new ShaderFragmentMain2Cycle(_glinfo)) -, m_fragmentBlendMux(new ShaderFragmentBlendMux(_glinfo)) -, m_fragmentReadTex0(new ShaderFragmentReadTex0(_glinfo)) -, m_fragmentReadTex1(new ShaderFragmentReadTex1(_glinfo)) -, m_fragmentCorrectTexCoords(new ShaderFragmentCorrectTexCoords()) -, m_fragmentTextureEngineTex0(new ShaderFragmentTextureEngineTex0(_glinfo)) -, m_fragmentTextureEngineTex1(new ShaderFragmentTextureEngineTex1(_glinfo)) -, m_fragmentReadTexCopyMode(new ShaderFragmentReadTexCopyMode(_glinfo)) -, m_fragmentReadTexMipmap(new ShaderFragmentReadTexMipmap(_glinfo)) -, m_fragmentCallN64Depth(new ShaderFragmentCallN64Depth(_glinfo)) -, m_fragmentRenderTarget(new ShaderFragmentRenderTarget(_glinfo)) -, m_shaderFragmentMainEnd(new ShaderFragmentMainEnd(_glinfo)) -, m_shaderNoise(new ShaderNoise(_glinfo)) -, m_shaderDither(new ShaderDither(_glinfo)) -, m_shaderWriteDepth(new ShaderWriteDepth(_glinfo)) -, m_shaderMipmap(new ShaderMipmap(_glinfo)) -, m_shaderCalcLight(new ShaderCalcLight(_glinfo)) -, m_shaderReadtex(new ShaderReadtex(_glinfo)) -, m_shaderReadtexCopyMode(new ShaderReadtexCopyMode(_glinfo)) -, m_shaderN64DepthCompare(new ShaderN64DepthCompare(_glinfo)) -, m_shaderN64DepthRender(new ShaderN64DepthRender(_glinfo)) -, m_shaderTextureEngine(new ShaderTextureEngine(_glinfo)) -, m_shaderCoverage(new ShaderCoverage()) +CombinerProgramBuilder::CombinerProgramBuilder(const opengl::GLInfo & _glinfo, opengl::CachedUseProgram * _useProgram, + std::unique_ptr _uniformFactory) +: m_uniformFactory(std::move(_uniformFactory)) , m_useProgram(_useProgram) -, m_combinerOptionsBits(graphics::CombinerProgram::getShaderCombinerOptionsBits()) , m_useCoverage(_glinfo.coverage && config.generalEmulation.enableCoverage != 0) { - m_vertexShaderRect = _createVertexShader(m_vertexHeader.get(), m_vertexRect.get(), m_vertexEnd.get()); - m_vertexShaderTriangle = _createVertexShader(m_vertexHeader.get(), m_vertexTriangle.get(), m_vertexEnd.get()); - m_vertexShaderTexturedRect = _createVertexShader(m_vertexHeader.get(), m_vertexTexturedRect.get(), m_vertexEnd.get()); - m_vertexShaderTexturedTriangle = _createVertexShader(m_vertexHeader.get(), m_vertexTexturedTriangle.get(), m_vertexEnd.get()); - m_uniformFactory.reset(new CombinerProgramUniformFactory(_glinfo)); } CombinerProgramBuilder::~CombinerProgramBuilder() { - glDeleteShader(m_vertexShaderRect); - glDeleteShader(m_vertexShaderTriangle); - glDeleteShader(m_vertexShaderTexturedRect); - glDeleteShader(m_vertexShaderTexturedTriangle); } -bool CombinerProgramBuilder::isObsolete() const -{ - return m_combinerOptionsBits != graphics::CombinerProgram::getShaderCombinerOptionsBits(); } diff --git a/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilder.h b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilder.h index 92698035..6910baff 100644 --- a/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilder.h +++ b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilder.h @@ -2,6 +2,8 @@ #include #include #include +#include "glsl_CombinerProgramUniformFactory.h" +#include "glsl_ShaderPart.h" namespace graphics { class CombinerProgram; @@ -12,98 +14,121 @@ namespace opengl { } namespace glsl { - - class ShaderPart; class CombinerInputs; - class CombinerProgramUniformFactory; +} - class CombinerProgramBuilder - { - public: - CombinerProgramBuilder(const opengl::GLInfo & _glinfo, opengl::CachedUseProgram * _useProgram); - ~CombinerProgramBuilder(); +namespace glsl { - graphics::CombinerProgram * buildCombinerProgram(Combiner & _color, Combiner & _alpha, const CombinerKey & _key); +class TextureConvert { +public: + void setMode(u32 _mode) { + m_mode = _mode; + } - const ShaderPart * getVertexShaderHeader() const; + bool getBilerp1() const { + return (m_mode & 1) != 0; + } - const ShaderPart * getFragmentShaderHeader() const; + bool getBilerp0() const { + return (m_mode & 2) != 0; + } - const ShaderPart * getFragmentShaderEnd() const; + bool useYUVCoversion() const { + return (m_mode & 3) != 3; + } - bool isObsolete() const; + bool useTextureFiltering() const { + return (m_mode & 3) != 0; + } - private: - CombinerInputs compileCombiner(const CombinerKey & _key, Combiner & _color, Combiner & _alpha, std::string & _strShader); +private: + u32 m_mode; +}; - typedef std::unique_ptr ShaderPartPtr; - ShaderPartPtr m_blender1; - ShaderPartPtr m_blender2; - ShaderPartPtr m_blenderAlpha; - ShaderPartPtr m_legacyBlender; - ShaderPartPtr m_clamp; - ShaderPartPtr m_signExtendColorC; - ShaderPartPtr m_signExtendAlphaC; - ShaderPartPtr m_signExtendColorABD; - ShaderPartPtr m_signExtendAlphaABD; - ShaderPartPtr m_alphaTest; - ShaderPartPtr m_callDither; +class CombinerProgramBuilder +{ +public: + using ShaderPartPtr = std::unique_ptr; - ShaderPartPtr m_vertexHeader; - ShaderPartPtr m_vertexEnd; - ShaderPartPtr m_vertexRect; - ShaderPartPtr m_vertexTexturedRect; - ShaderPartPtr m_vertexTriangle; - ShaderPartPtr m_vertexTexturedTriangle; + CombinerProgramBuilder(const opengl::GLInfo & _glinfo, opengl::CachedUseProgram * _useProgram, + std::unique_ptr _uniformFactory); + virtual ~CombinerProgramBuilder(); - ShaderPartPtr m_fragmentHeader; - ShaderPartPtr m_fragmentGlobalVariablesTex; - ShaderPartPtr m_fragmentGlobalVariablesNotex; - ShaderPartPtr m_fragmentHeaderNoise; - ShaderPartPtr m_fragmentHeaderWriteDepth; - ShaderPartPtr m_fragmentHeaderCalcLight; - ShaderPartPtr m_fragmentHeaderMipMap; - ShaderPartPtr m_fragmentHeaderTextureEngine; - ShaderPartPtr m_fragmentHeaderReadMSTex; - ShaderPartPtr m_fragmentHeaderDither; - ShaderPartPtr m_fragmentHeaderDepthCompare; - ShaderPartPtr m_fragmentHeaderReadTex; - ShaderPartPtr m_fragmentHeaderReadTexCopyMode; - ShaderPartPtr m_fragmentMain; - ShaderPartPtr m_fragmentMain2Cycle; - ShaderPartPtr m_fragmentBlendMux; - ShaderPartPtr m_fragmentReadTex0; - ShaderPartPtr m_fragmentReadTex1; - ShaderPartPtr m_fragmentCorrectTexCoords; - ShaderPartPtr m_fragmentTextureEngineTex0; - ShaderPartPtr m_fragmentTextureEngineTex1; - ShaderPartPtr m_fragmentReadTexCopyMode; - ShaderPartPtr m_fragmentReadTexMipmap; - ShaderPartPtr m_fragmentCallN64Depth; - ShaderPartPtr m_fragmentRenderTarget; - ShaderPartPtr m_shaderFragmentMainEnd; + graphics::CombinerProgram * buildCombinerProgram(Combiner & _color, Combiner & _alpha, const CombinerKey & _key); - ShaderPartPtr m_shaderNoise; - ShaderPartPtr m_shaderDither; - ShaderPartPtr m_shaderWriteDepth; - ShaderPartPtr m_shaderMipmap; - ShaderPartPtr m_shaderCalcLight; - ShaderPartPtr m_shaderReadtex; - ShaderPartPtr m_shaderReadtexCopyMode; - ShaderPartPtr m_shaderN64DepthCompare; - ShaderPartPtr m_shaderN64DepthRender; - ShaderPartPtr m_shaderTextureEngine; - ShaderPartPtr m_shaderCoverage; + virtual const ShaderPart * getVertexShaderHeader() const = 0; - std::unique_ptr m_uniformFactory; + virtual const ShaderPart * getFragmentShaderHeader() const = 0; - GLuint m_vertexShaderRect; - GLuint m_vertexShaderTriangle; - GLuint m_vertexShaderTexturedRect; - GLuint m_vertexShaderTexturedTriangle; - opengl::CachedUseProgram * m_useProgram; - u32 m_combinerOptionsBits; - bool m_useCoverage = false; - }; + virtual const ShaderPart * getFragmentShaderEnd() const = 0; + + virtual bool isObsolete() const = 0; + + static u32 s_cycleType; + static TextureConvert s_textureConvert; + +private: + CombinerInputs compileCombiner(const CombinerKey & _key, Combiner & _color, Combiner & _alpha, std::string & _strShader); + + virtual void _writeSignExtendAlphaC(std::stringstream& ssShader) const = 0; + virtual void _writeSignExtendAlphaABD(std::stringstream& ssShader) const = 0; + virtual void _writeAlphaTest(std::stringstream& ssShader) const = 0; + virtual void _writeSignExtendColorC(std::stringstream& ssShader) const = 0; + virtual void _writeSignExtendColorABD(std::stringstream& ssShader) const = 0; + virtual void _writeClamp(std::stringstream& ssShader) const = 0; + virtual void _writeCallDither(std::stringstream& ssShader) const = 0; + virtual void _writeBlender1(std::stringstream& ssShader) const = 0; + virtual void _writeBlender2(std::stringstream& ssShader) const = 0; + virtual void _writeBlenderAlpha(std::stringstream& ssShader) const = 0; + virtual void _writeLegacyBlender(std::stringstream& ssShader) const = 0; + virtual void _writeFragmentHeader(std::stringstream& ssShader) const = 0; + virtual void _writeFragmentGlobalVariablesTex(std::stringstream& ssShader) const = 0; + virtual void _writeFragmentHeaderDither(std::stringstream& ssShader) const = 0; + virtual void _writeFragmentHeaderNoise(std::stringstream& ssShader) const = 0; + virtual void _writeFragmentHeaderWriteDepth(std::stringstream& ssShader) const = 0; + virtual void _writeFragmentHeaderDepthCompare(std::stringstream& ssShader) const = 0; + virtual void _writeFragmentHeaderReadMSTex(std::stringstream& ssShader) const = 0; + virtual void _writeFragmentHeaderClampWrapMirrorEngine(std::stringstream& ssShader) const = 0; + virtual void _writeFragmentHeaderMipMap(std::stringstream& ssShader) const = 0; + virtual void _writeFragmentHeaderReadTex(std::stringstream& ssShader) const = 0; + virtual void _writeFragmentHeaderReadTexCopyMode(std::stringstream& ssShader) const = 0; + virtual void _writeFragmentGlobalVariablesNotex(std::stringstream& ssShader) const = 0; + virtual void _writeFragmentHeaderCalcLight(std::stringstream& ssShader) const = 0; + virtual void _writeFragmentMain2Cycle(std::stringstream& ssShader) const = 0; + virtual void _writeFragmentMain(std::stringstream& ssShader) const = 0; + virtual void _writeFragmentBlendMux(std::stringstream& ssShader) const = 0; + virtual void _writeShaderCoverage(std::stringstream& ssShader) const = 0; + virtual void _writeFragmentCorrectTexCoords(std::stringstream& ssShader) const = 0; + virtual void _writeFragmentClampWrapMirrorEngineTex0(std::stringstream& ssShader) const = 0; + virtual void _writeFragmentClampWrapMirrorEngineTex1(std::stringstream& ssShader) const = 0; + virtual void _writeFragmentReadTexMipmap(std::stringstream& ssShader) const = 0; + virtual void _writeFragmentReadTex0(std::stringstream& ssShader) const = 0; + virtual void _writeFragmentReadTex1(std::stringstream& ssShader) const = 0; + virtual void _writeFragmentReadTexCopyMode(std::stringstream& ssShader) const = 0; + virtual void _writeFragmentCallN64Depth(std::stringstream& ssShader) const = 0; + virtual void _writeFragmentRenderTarget(std::stringstream& ssShader) const = 0; + virtual void _writeShaderFragmentMainEnd(std::stringstream& ssShader) const = 0; + virtual void _writeShaderCalcLight(std::stringstream& ssShader) const = 0; + virtual void _writeShaderClampWrapMirrorEngine(std::stringstream& ssShader) const = 0; + virtual void _writeShaderMipmap(std::stringstream& ssShader) const = 0; + virtual void _writeShaderReadtex(std::stringstream& ssShader) const = 0; + virtual void _writeShaderReadtexCopyMode(std::stringstream& ssShader) const = 0; + virtual void _writeShaderNoise(std::stringstream& ssShader) const = 0; + virtual void _writeShaderDither(std::stringstream& ssShader) const = 0; + virtual void _writeShaderWriteDepth(std::stringstream& ssShader) const = 0; + virtual void _writeShaderN64DepthCompare(std::stringstream& ssShader) const = 0; + virtual void _writeShaderN64DepthRender(std::stringstream& ssShader) const = 0; + + virtual GLuint _getVertexShaderRect() const = 0; + virtual GLuint _getVertexShaderTriangle() const = 0; + virtual GLuint _getVertexShaderTexturedRect() const = 0; + virtual GLuint _getVertexShaderTexturedTriangle() const = 0; + + std::unique_ptr m_uniformFactory; + opengl::CachedUseProgram * m_useProgram; + bool m_useCoverage = false; + +}; } + diff --git a/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilderAccurate.cpp b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilderAccurate.cpp new file mode 100644 index 00000000..ef594ade --- /dev/null +++ b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilderAccurate.cpp @@ -0,0 +1,1238 @@ +#include // for setprecision +#include +#include +#include +#include "glsl_Utils.h" +#include "glsl_CombinerInputs.h" +#include "glsl_CombinerProgramImpl.h" +#include "glsl_CombinerProgramBuilderAccurate.h" +#include "glsl_CombinerProgramUniformFactoryAccurate.h" +#include "GraphicsDrawer.h" + +namespace glsl { + +class VertexShaderTexturedTriangle : public ShaderPart +{ +public: + VertexShaderTexturedTriangle(const opengl::GLInfo & _glinfo) + { + m_part = + "IN highp vec4 aPosition; \n" + "IN lowp vec4 aColor; \n" + "IN highp vec2 aTexCoord; \n" + "IN lowp float aNumLights; \n" + "IN highp vec4 aModify; \n" + "IN highp vec2 aBaryCoords; \n" + " \n" + "uniform int uTexturePersp; \n" + "uniform lowp int uTextureFilterMode; \n" + " \n" + "uniform lowp int uFogUsage; \n" + "uniform mediump vec2 uFogScale; \n" + "uniform mediump vec2 uScreenCoordsScale; \n" + " \n" + "uniform mediump vec2 uTexScale; \n" + "uniform mediump vec2 uVTrans; \n" + "uniform mediump vec2 uVScale; \n" + "uniform mediump vec2 uAdjustTrans; \n" + "uniform mediump vec2 uAdjustScale; \n" + "uniform lowp ivec2 uCacheFrameBuffer; \n" + "OUT highp vec2 vTexCoord0; \n" + "OUT highp vec2 vTexCoord1; \n" + "OUT mediump vec2 vLodTexCoord; \n" + "OUT lowp float vNumLights; \n" + "OUT lowp vec4 vShadeColor; \n" + "OUT highp vec4 vBaryCoords; \n" + ; + if (!_glinfo.isGLESX || _glinfo.noPerspective) + m_part += "noperspective OUT lowp vec4 vShadeColorNoperspective;\n"; + else + m_part += "OUT lowp vec4 vShadeColorNoperspective; \n"; + m_part += + "void main() \n" + "{ \n" + " gl_Position = aPosition; \n" + " vShadeColor = aColor; \n" + " vec2 texCoord = aTexCoord; \n" + " texCoord *= uTexScale; \n" + " if (uTexturePersp == 0 && aModify[2] == 0.0) texCoord *= 0.5;\n" + " vTexCoord0 = texCoord; \n" + " vTexCoord1 = texCoord; \n" + " vLodTexCoord = texCoord; \n" + " vNumLights = aNumLights; \n" + " if ((aModify[0]) != 0.0) { \n" + " gl_Position.xy *= gl_Position.w; \n" + " } \n" + " else { \n" + " gl_Position.xy = gl_Position.xy * uVScale.xy + uVTrans.xy * gl_Position.ww; \n" + " gl_Position.xy = floor(gl_Position.xy * vec2(4.0)) * vec2(0.25); \n" + " gl_Position.xy = gl_Position.xy * uAdjustScale + gl_Position.ww * uAdjustTrans; \n" + " } \n" + " if ((aModify[1]) != 0.0) \n" + " gl_Position.z *= gl_Position.w; \n" + " if ((aModify[3]) != 0.0) \n" + " vNumLights = 0.0; \n" + " if (uFogUsage > 0) { \n" + " lowp float fp; \n" + " if (aPosition.z < -aPosition.w && aModify[1] == 0.0) \n" + " fp = -uFogScale.s + uFogScale.t; \n" + " else \n" + " fp = aPosition.z/aPosition.w*uFogScale.s + uFogScale.t; \n" + " fp = clamp(fp, 0.0, 1.0); \n" + " if (uFogUsage == 1) \n" + " vShadeColor.a = fp; \n" + " else \n" + " vShadeColor.rgb = vec3(fp); \n" + " } \n" + " vBaryCoords = vec4(aBaryCoords, 1.0 - aBaryCoords.x - aBaryCoords.y, 0.5); \n" + " vShadeColorNoperspective = vShadeColor; \n" + ; + } +}; + +class ShaderFragmentGlobalVariablesTex : public ShaderPart +{ +public: + ShaderFragmentGlobalVariablesTex(const opengl::GLInfo & _glinfo) + { + m_part = + "uniform sampler2D uTex0; \n" + "uniform sampler2D uTex1; \n" + "uniform lowp vec4 uFogColor; \n" + "uniform lowp vec4 uCenterColor;\n" + "uniform lowp vec4 uScaleColor; \n" + "uniform lowp vec4 uBlendColor; \n" + "uniform lowp vec4 uEnvColor; \n" + "uniform lowp vec4 uPrimColor; \n" + "uniform lowp float uPrimLod; \n" + "uniform lowp float uK4; \n" + "uniform lowp float uK5; \n" + "uniform lowp int uAlphaCompareMode; \n" + "uniform lowp ivec2 uFbMonochrome; \n" + "uniform lowp ivec2 uFbFixedAlpha; \n" + "uniform lowp int uEnableAlphaTest; \n" + "uniform lowp int uCvgXAlpha; \n" + "uniform lowp int uAlphaCvgSel; \n" + "uniform lowp float uAlphaTestValue; \n" + "uniform lowp int uDepthSource; \n" + "uniform highp float uPrimDepth; \n" + "uniform mediump vec2 uScreenScale; \n" + "uniform highp vec2 uTexClamp[2]; \n" + "uniform highp vec2 uTexWrap[2]; \n" + "uniform lowp vec2 uTexWrapEn[2]; \n" + "uniform lowp vec2 uTexMirrorEn[2]; \n" + "uniform lowp vec2 uTexClampEn[2]; \n" + "uniform highp vec2 uTexSize[2]; \n" + "uniform highp vec2 uShiftScale[2]; \n" + "uniform highp vec2 uTexOffset[2]; \n" + "uniform highp vec2 uHDRatio[2]; \n" + "uniform highp vec2 uTexCoordOffset[2]; \n" + "uniform highp vec2 uBilinearOffset; \n" + "uniform highp vec2 uCacheOffset[2]; \n" + "uniform lowp int uUseTexCoordBounds; \n" + "uniform highp vec4 uTexCoordBounds0; \n" + "uniform highp vec4 uTexCoordBounds1; \n" + "uniform lowp int uScreenSpaceTriangle; \n" + "highp vec2 texCoord0; \n" + "highp vec2 texCoord1; \n" + "highp vec2 tcData0[5]; \n" + "highp vec2 tcData1[5]; \n" + "uniform lowp int uCvgDest; \n" + "uniform lowp int uBlendAlphaMode; \n" + "lowp float cvg; \n" + ; + + if (config.generalEmulation.enableLegacyBlending != 0) { + m_part += + "uniform lowp int uFogUsage; \n" + ; + } else { + m_part += + "uniform lowp ivec4 uBlendMux1; \n" + "uniform lowp int uForceBlendCycle1;\n" + ; + } + + if (!_glinfo.isGLES2) { + m_part += + "uniform sampler2D uDepthTex; \n" + "uniform lowp int uAlphaDitherMode; \n" + "uniform lowp int uColorDitherMode; \n" + "uniform lowp int uRenderTarget; \n" + "uniform mediump vec2 uDepthScale; \n" + ; + if (config.frameBufferEmulation.N64DepthCompare != Config::dcDisable) { + m_part += + "uniform lowp int uEnableDepthCompare; \n" + ; + } + } else { + m_part += + "lowp int nCurrentTile; \n" + ; + } + + if (config.video.multisampling > 0) { + m_part += + "uniform lowp ivec2 uMSTexEnabled; \n" + "uniform lowp sampler2DMS uMSTex0; \n" + "uniform lowp sampler2DMS uMSTex1; \n" + ; + } + + if (!_glinfo.isGLESX || _glinfo.noPerspective) + m_part += "noperspective IN lowp vec4 vShadeColorNoperspective; \n"; + else + m_part += "IN lowp vec4 vShadeColorNoperspective; \n"; + + m_part += + "IN lowp vec4 vShadeColor; \n" + "IN highp vec2 vTexCoord0; \n" + "IN highp vec2 vTexCoord1; \n" + "IN mediump vec2 vLodTexCoord; \n" + "IN lowp float vNumLights; \n" + "IN highp vec4 vBaryCoords; \n" + ; + + if (_glinfo.dual_source_blending) { + m_part += + "layout(location = 0, index = 0) OUT lowp vec4 fragColor; \n" // MAIN FRAGMENT SHADER OUTPUT + "layout(location = 0, index = 1) OUT lowp vec4 fragColor1; \n" // SECONDARY FRAGMENT SHADER OUTPUT + "#define LAST_FRAG_COLOR vec4(0.0) \n" // DUMMY + "#define LAST_FRAG_ALPHA 1.0 \n" // DUMMY + ; + } else if (_glinfo.ext_fetch) { + m_part += + "layout(location = 0) inout lowp vec4 fragColor; \n" // MAIN FRAGMENT SHADER OUTPUT + "lowp vec4 fragColor1; \n" // DUMMY + "#define LAST_FRAG_COLOR fragColor \n" // CURRENT FRAMEBUFFER COLOR/ALPHA + "#define LAST_FRAG_ALPHA fragColor.a \n" // CURRENT FRAMEBUFFER ALPHA + ; + } else if (_glinfo.ext_fetch_arm) { + m_part += + "OUT lowp vec4 fragColor; \n" // MAIN FRAGMENT SHADER OUTPUT + "lowp vec4 fragColor1; \n" // DUMMY + "#define LAST_FRAG_COLOR gl_LastFragColorARM \n" // CURRENT FRAMEBUFFER COLOR/ALPHA + "#define LAST_FRAG_ALPHA gl_LastFragColorARM.a \n" // CURRENT FRAMEBUFFER ALPHA + ; + } else { + m_part += + "OUT lowp vec4 fragColor; \n" // MAIN FRAGMENT SHADER OUTPUT + "lowp vec4 fragColor1; \n" // DUMMY + "#define LAST_FRAG_COLOR vec4(0.0) \n" // DUMMY + "#define LAST_FRAG_ALPHA 1.0 \n" // DUMMY + ; + } + + if (config.frameBufferEmulation.N64DepthCompare == Config::dcFast && _glinfo.n64DepthWithFbFetch) { + m_part += + "layout(location = 1) inout highp vec4 depthZ; \n" + "layout(location = 2) inout highp vec4 depthDeltaZ; \n" + ; + } + + if (_glinfo.isGLES2) + m_part += + "uniform mediump vec2 uTextureSize[2]; \n" + ; + } +}; + +class ShaderFragmentHeaderTextureEngine : public ShaderPart +{ +public: + ShaderFragmentHeaderTextureEngine(const opengl::GLInfo & _glinfo) + { + m_part = + "highp vec2 clampWrapMirror(in highp vec2 vTexCoord, \n" + " in highp vec2 vWrap, in highp vec2 vClamp, \n" + " in lowp vec2 vClampEn, in lowp vec2 vMirrorEn ); \n" + "void textureEngine0(in highp vec2 texCoord, out highp vec2 tcData[5]); \n" + "void textureEngine1(in highp vec2 texCoord, out highp vec2 tcData[5]); \n" + ; + } +}; + +class ShaderFragmentHeaderReadMSTex : public ShaderPart +{ +public: + ShaderFragmentHeaderReadMSTex(const opengl::GLInfo & _glinfo) : m_glinfo(_glinfo) + { + } + + void write(std::stringstream & shader) const override + { + if (!m_glinfo.isGLES2 && + config.video.multisampling > 0 && + (CombinerProgramBuilder::s_cycleType == G_CYC_COPY || CombinerProgramBuilder::s_textureConvert.useTextureFiltering())) + { + shader << + "lowp vec4 readTexMS(in lowp sampler2DMS mstex, in highp vec2 tcData[5], in lowp int fbMonochrome, in lowp int fbFixedAlpha);\n"; + } + } + +private: + const opengl::GLInfo& m_glinfo; +}; + +class ShaderFragmentHeaderReadTex : public ShaderPart +{ +public: + ShaderFragmentHeaderReadTex(const opengl::GLInfo & _glinfo) : m_glinfo(_glinfo) + { + } + + void write(std::stringstream & shader) const override + { + std::string shaderPart; + if (!m_glinfo.isGLES2) { + + if (CombinerProgramBuilder::s_textureConvert.useTextureFiltering()) { + shaderPart += "uniform lowp int uTextureFilterMode; \n"; + shaderPart += "#define TEX_NEAREST(name, tex, tcData) \\\n" + "{ \\\n" + " name = texelFetch(tex, ivec2(tcData[0]), 0); \\\n" + "} \n" + ; + switch (config.texture.bilinearMode + config.texture.enableHalosRemoval * 2) { + case BILINEAR_3POINT: + // 3 point texture filtering. + // Original author: ArthurCarvalho + // GLSL implementation: twinaphex, mupen64plus-libretro project. + shaderPart += + "#define TEX_FILTER(name, tex, tcData) \\\n" + " { \\\n" + " lowp float bottomRightTri = step(1.0, tcData[4].s + tcData[4].t); \\\n" + " lowp vec4 c00 = texelFetch(tex, ivec2(tcData[0]), 0); \\\n" + " lowp vec4 c01 = texelFetch(tex, ivec2(tcData[1]), 0); \\\n" + " lowp vec4 c10 = texelFetch(tex, ivec2(tcData[2]), 0); \\\n" + " lowp vec4 c11 = texelFetch(tex, ivec2(tcData[3]), 0); \\\n" + " lowp vec4 c0 = c00 + tcData[4].s*(c10-c00) + tcData[4].t*(c01-c00); \\\n" + " lowp vec4 c1 = c11 + (1.0-tcData[4].s)*(c01-c11) + (1.0-tcData[4].t)*(c10-c11); \\\n" + " name = c0 + bottomRightTri * (c1-c0); \\\n" + " } \n" + ; + break; + case BILINEAR_STANDARD: + shaderPart += + "#define TEX_FILTER(name, tex, tcData) \\\n" + "{ \\\n" + " lowp vec4 c00 = texelFetch(tex, ivec2(tcData[0]), 0); \\\n" + " lowp vec4 c01 = texelFetch(tex, ivec2(tcData[1]), 0); \\\n" + " lowp vec4 c10 = texelFetch(tex, ivec2(tcData[2]), 0); \\\n" + " lowp vec4 c11 = texelFetch(tex, ivec2(tcData[3]), 0); \\\n" + " lowp vec4 c0 = c00 + tcData[4].s * (c10-c00); \\\n" + " lowp vec4 c1 = c01 + tcData[4].s * (c11-c01); \\\n" + " name = c0 + tcData[4].t * (c1-c0); \\\n" + "} \n" + ; + break; + case BILINEAR_3POINT_WITH_COLOR_BLEEDING: + // 3 point texture filtering. + // Original author: ArthurCarvalho + // GLSL implementation: twinaphex, mupen64plus-libretro project. + shaderPart += + "#define TEX_FILTER(name, tex, tcData) \\\n" + "{ \\\n" + " lowp float bottomRightTri = step(1.0, tcData[4].s + tcData[4].t); \\\n" + " lowp vec4 c00 = texelFetch(tex, ivec2(tcData[0]), 0); \\\n" + " lowp vec4 c01 = texelFetch(tex, ivec2(tcData[1]), 0); \\\n" + " lowp vec4 c10 = texelFetch(tex, ivec2(tcData[2]), 0); \\\n" + " lowp vec4 c11 = texelFetch(tex, ivec2(tcData[3]), 0); \\\n" + " if(uEnableAlphaTest == 1 ){ \\\n" // Calculate premultiplied color values + " c00.rgb *= c00.a; \\\n" + " c01.rgb *= c01.a; \\\n" + " c10.rgb *= c10.a; \\\n" + " c11.rgb *= c11.a; \\\n" + " } \\\n" + " lowp vec4 c0 = c00 + tcData[4].s*(c10-c00) + tcData[4].t*(c01-c00); \\\n" + " lowp vec4 c1 = c11 + (1.0-tcData[4].s)*(c01-c11) + (1.0-tcData[4].t)*(c10-c11); \\\n" + " name = c0 + bottomRightTri * (c1-c0); \\\n" + " if(uEnableAlphaTest == 1 ) name.rgb /= name.a; \\\n" // Divide alpha to get actual color value + "} \n" + ; + break; + case BILINEAR_STANDARD_WITH_COLOR_BLEEDING_AND_PREMULTIPLIED_ALPHA: + shaderPart += + "#define TEX_FILTER(name, tex, tcData) \\\n" + "{ \\\n" + " lowp vec4 c00 = texelFetch(tex, ivec2(tcData[0]), 0); \\\n" + " lowp vec4 c01 = texelFetch(tex, ivec2(tcData[1]), 0); \\\n" + " lowp vec4 c10 = texelFetch(tex, ivec2(tcData[2]), 0); \\\n" + " lowp vec4 c11 = texelFetch(tex, ivec2(tcData[3]), 0); \\\n" + " if(uEnableAlphaTest == 1){ \\\n" // Calculate premultiplied color values + " c00.rgb *= c00.a; \\\n" + " c01.rgb *= c01.a; \\\n" + " c10.rgb *= c10.a; \\\n" + " c11.rgb *= c11.a; \\\n" + " } \\\n" + " lowp vec4 c0 = c00 + tcData[4].s * (c10-c00); \\\n" + " lowp vec4 c1 = c01 + tcData[4].s * (c11-c01); \\\n" + " name = c0 + tcData[4].t * (c1-c0); \\\n" + " if(uEnableAlphaTest == 1) name.rgb /= name.a; \\\n" + "} \n" + ; + break; + } + shaderPart += + "#define READ_TEX(name, tex, tcData, fbMonochrome, fbFixedAlpha) \\\n" + " { \\\n" + " if (fbMonochrome == 3) { \\\n" + " mediump ivec2 coord = ivec2(gl_FragCoord.xy); \\\n" + " name = texelFetch(tex, coord, 0); \\\n" + " } else { \\\n" + " if (uTextureFilterMode == 0) \\\n" + " { \\\n" + " TEX_NEAREST(name, tex, tcData); \\\n" + " } \\\n" + " else TEX_FILTER(name, tex, tcData); \\\n" + " } \\\n" + " if (fbMonochrome == 1) name = vec4(name.r); \\\n" + " else if (fbMonochrome == 2) \\\n" + " name.rgb = vec3(dot(vec3(0.2126, 0.7152, 0.0722), name.rgb)); \\\n" + " else if (fbMonochrome == 3) { \\\n" + " name.rgb = vec3(dot(vec3(0.2126, 0.7152, 0.0722), name.rgb)); \\\n" + " name.a = 0.0; \\\n" + " } \\\n" + " if (fbFixedAlpha == 1) name.a = 0.825; \\\n" + " } \n" + ; + } + + if (CombinerProgramBuilder::s_textureConvert.useYUVCoversion()) { + shaderPart += + "uniform lowp ivec2 uTextureFormat; \n" + "uniform lowp int uTextureConvert; \n" + "uniform mediump ivec4 uConvertParams; \n" + "#define YUVCONVERT(name, format) \\\n" + " mediump ivec4 icolor = ivec4(name*255.0); \\\n" + " if (format == 1) \\\n" + " icolor.rg -= 128; \\\n" + " mediump ivec4 iconvert; \\\n" + " iconvert.r = icolor.b + (uConvertParams[0]*icolor.g + 128)/256; \\\n" + " iconvert.g = icolor.b + (uConvertParams[1]*icolor.r + uConvertParams[2]*icolor.g + 128)/256; \\\n" + " iconvert.b = icolor.b + (uConvertParams[3]*icolor.r + 128)/256; \\\n" + " iconvert.a = icolor.b; \\\n" + " name = vec4(iconvert)/255.0; \n" + "#define YUVCONVERT_TEX0(name, tex, tcData, format) \\\n" + " { \\\n" + " name = texelFetch(tex, ivec2(tcData[0]), 0); \\\n" + " YUVCONVERT(name, format) \\\n" + " } \n" + "#define YUVCONVERT_TEX1(name, tex, tcData, format, prev) \\\n" + " { \\\n" + " if (uTextureConvert != 0) name = prev; \\\n" + " else name = texelFetch(tex, ivec2(tcData[0]), 0); \\\n" + " YUVCONVERT(name, format) \\\n" + " } \n" + ; + } + + } else { + if (CombinerProgramBuilder::s_textureConvert.useTextureFiltering()) { + shaderPart += + "uniform lowp int uTextureFilterMode; \n" + "lowp vec4 readTex(in sampler2D tex, in highp vec2 tcData[5], in lowp int fbMonochrome, in lowp int fbFixedAlpha); \n" + ; + } + if (CombinerProgramBuilder::s_textureConvert.useYUVCoversion()) { + shaderPart += + "uniform lowp ivec2 uTextureFormat; \n" + "uniform lowp int uTextureConvert; \n" + "uniform mediump ivec4 uConvertParams; \n" + "lowp vec4 YUV_Convert(in sampler2D tex, in highp vec2 tcData[5], in lowp int convert, in lowp int format, in lowp vec4 prev); \n" + ; + } + } + + shader << shaderPart; + } + +private: + const opengl::GLInfo& m_glinfo; +}; + +class ShaderFragmentHeaderReadTexCopyMode : public ShaderPart +{ +public: + ShaderFragmentHeaderReadTexCopyMode (const opengl::GLInfo & _glinfo) + { + if (!_glinfo.isGLES2) { + m_part = + "#define READ_TEX(name, tex, tcData, fbMonochrome, fbFixedAlpha) \\\n" + " { \\\n" + " if (fbMonochrome == 3) { \\\n" + " mediump ivec2 coord = ivec2(gl_FragCoord.xy); \\\n" + " name = texelFetch(tex, coord, 0); \\\n" + " } else { \\\n" + " name = texelFetch(tex, ivec2(tcData[0]),0); \\\n" + " } \\\n" + " if (fbMonochrome == 1) name = vec4(name.r); \\\n" + " else if (fbMonochrome == 2) \\\n" + " name.rgb = vec3(dot(vec3(0.2126, 0.7152, 0.0722), name.rgb)); \\\n" + " else if (fbMonochrome == 3) { \\\n" + " name.rgb = vec3(dot(vec3(0.2126, 0.7152, 0.0722), name.rgb)); \\\n" + " name.a = 0.0; \\\n" + " } \\\n" + " if (fbFixedAlpha == 1) name.a = 0.825; \\\n" + " } \n" + ; + } else { + m_part = + "lowp vec4 readTex(in sampler2D tex, in highp vec2 tcData[5], in lowp int fbMonochrome, in lowp int fbFixedAlpha); \n" + ; + } + } +}; + +class ShaderFragmentReadTexCopyMode : public ShaderPart +{ +public: + ShaderFragmentReadTexCopyMode(const opengl::GLInfo & _glinfo) + { + if (_glinfo.isGLES2) { + m_part = + " nCurrentTile = 0; \n" + " lowp vec4 readtex0 = readTex(uTex0, tcData0, uFbMonochrome[0], uFbFixedAlpha[0]); \n" + ; + } else { + if (config.video.multisampling > 0) { + m_part = + " lowp vec4 readtex0; \n" + " if (uMSTexEnabled[0] == 0) { \n" + " READ_TEX(readtex0, uTex0, tcData0, uFbMonochrome[0], uFbFixedAlpha[0]) \n" + " } else readtex0 = readTexMS(uMSTex0, tcData0, uFbMonochrome[0], uFbFixedAlpha[0]);\n" + ; + } else { + m_part = + " lowp vec4 readtex0; \n" + " READ_TEX(readtex0, uTex0, tcData0, uFbMonochrome[0], uFbFixedAlpha[0]) \n" + ; + } + } + } +}; + +class ShaderFragmentReadTex0 : public ShaderPart +{ +public: + ShaderFragmentReadTex0(const opengl::GLInfo & _glinfo) : m_glinfo(_glinfo) + { + } + + void write(std::stringstream & shader) const override + { + std::string shaderPart; + + if (m_glinfo.isGLES2) { + + shaderPart = " nCurrentTile = 0; \n"; + if (CombinerProgramBuilder::s_textureConvert.getBilerp0()) { + shaderPart += " lowp vec4 readtex0 = readTex(uTex0, tcData0, uFbMonochrome[0], uFbFixedAlpha[0]); \n"; + } else { + shaderPart += " lowp vec4 tmpTex = vec4(0.0); \n" + " lowp vec4 readtex0 = YUV_Convert(uTex0, tcData0, 0, uTextureFormat[0], tmpTex); \n"; + } + + } else { + + if (!CombinerProgramBuilder::s_textureConvert.getBilerp0()) { + shaderPart = " lowp vec4 readtex0; \n" + " YUVCONVERT_TEX0(readtex0, uTex0, tcData0, uTextureFormat[0]) \n"; + } else { + if (config.video.multisampling > 0) { + shaderPart = + " lowp vec4 readtex0; \n" + " if (uMSTexEnabled[0] == 0) { \n" + " READ_TEX(readtex0, uTex0, tcData0, uFbMonochrome[0], uFbFixedAlpha[0]) \n" + " } else readtex0 = readTexMS(uMSTex0, tcData0, uFbMonochrome[0], uFbFixedAlpha[0]); \n"; + } else { + shaderPart = " lowp vec4 readtex0; \n" + " READ_TEX(readtex0, uTex0, tcData0, uFbMonochrome[0], uFbFixedAlpha[0]) \n"; + } + } + + } + + shader << shaderPart; + } + +private: + const opengl::GLInfo& m_glinfo; +}; + +class ShaderFragmentReadTex1 : public ShaderPart +{ +public: + ShaderFragmentReadTex1(const opengl::GLInfo & _glinfo) : m_glinfo(_glinfo) + { + } + + void write(std::stringstream & shader) const override + { + std::string shaderPart; + + if (m_glinfo.isGLES2) { + + shaderPart = " nCurrentTile = 1; \n"; + + if (CombinerProgramBuilder::s_textureConvert.getBilerp1()) { + shaderPart += " lowp vec4 readtex1 = readTex(uTex1, tcData1, uFbMonochrome[1], uFbFixedAlpha[1]); \n"; + } else { + shaderPart += " lowp vec4 readtex1 = YUV_Convert(uTex1, tcData1, uTextureConvert, uTextureFormat[1], readtex0); \n"; + } + + } else { + + if (!CombinerProgramBuilder::s_textureConvert.getBilerp1()) { + shaderPart = + " lowp vec4 readtex1; \n" + " YUVCONVERT_TEX1(readtex1, uTex1, tcData1, uTextureFormat[1], readtex0) \n"; + } else { + if (config.video.multisampling > 0) { + shaderPart = + " lowp vec4 readtex1; \n" + " if (uMSTexEnabled[1] == 0) { \n" + " READ_TEX(readtex1, uTex1, tcData1, uFbMonochrome[1], uFbFixedAlpha[1]) \n" + " } else readtex1 = readTexMS(uMSTex1, tcData1, uFbMonochrome[1], uFbFixedAlpha[1]); \n"; + } else { + shaderPart = " lowp vec4 readtex1; \n" + " READ_TEX(readtex1, uTex1, tcData1, uFbMonochrome[1], uFbFixedAlpha[1]) \n"; + + } + } + + } + + shader << shaderPart; + } + +private: + const opengl::GLInfo& m_glinfo; +}; + +class ShaderMipmap : public ShaderPart +{ +public: + ShaderMipmap(const opengl::GLInfo & _glinfo) + { + if (_glinfo.isGLES2) { + static const std::string strReadTex0 = + "lowp vec4 TextureMipMap0(in sampler2D tex, in highp vec2 tcData[5]) \n" + "{ \n" + " mediump vec2 texSize = uTextureSize[0]; \n" + " lowp vec4 c00 = texture2D(tex, (tcData[0] + 0.5)/texSize); \n" + " lowp vec4 c01 = texture2D(tex, (tcData[1] + 0.5)/texSize); \n" + " lowp vec4 c10 = texture2D(tex, (tcData[2] + 0.5)/texSize); \n" + " lowp vec4 c11 = texture2D(tex, (tcData[3] + 0.5)/texSize); \n" + ; + static const std::string strReadTex1 = + "lowp vec4 TextureMipMap1(in sampler2D tex, in highp vec2 tcData[5], in lowp float lod) \n" + "{ \n" + // Fetch from texture atlas + // First 8 texels contain info about tile size and offset, 1 texel per tile + " mediump vec2 texSize = uTextureSize[1]; \n" + " mediump vec4 texWdthAndOff0 = 255.0 * texture2D(tex, vec2(0.5, 0.5)/texSize); \n" + " mediump vec4 texWdthAndOff = 255.0 * texture2D(tex, vec2(lod + 0.5, 0.5)/texSize); \n" + " mediump vec2 lod_scale = texWdthAndOff.ba / texWdthAndOff0.ba; \n" + " mediump float offset = texWdthAndOff.r + texWdthAndOff.g * 256.0; \n" + " mediump float width = texWdthAndOff.b; \n" + " mediump vec2 Coords00 = floor(tcData[0] * lod_scale); \n" + " mediump float offset00 = offset + width * Coords00.t + Coords00.s; \n" + " mediump float Y00 = floor(offset00 / mipmapTileWidth); \n" + " lowp vec4 c00 = texture2D(tex, (vec2(offset00 - mipmapTileWidth * Y00, Y00) + 0.5)/texSize); \n" + " mediump vec2 Coords01 = floor(tcData[1] * lod_scale); \n" + " mediump float offset01 = offset + width * Coords01.t + Coords01.s; \n" + " mediump float Y01 = floor(offset01 / mipmapTileWidth); \n" + " lowp vec4 c01 = texture2D(tex, (vec2(offset01 - mipmapTileWidth * Y01, Y01) + 0.5)/texSize); \n" + " mediump vec2 Coords10 = floor(tcData[2] * lod_scale); \n" + " mediump float offset10 = offset + width * Coords10.t + Coords10.s; \n" + " mediump float Y10 = floor(offset10 / mipmapTileWidth); \n" + " lowp vec4 c10 = texture2D(tex, (vec2(offset10 - mipmapTileWidth * Y10, Y10) + 0.5)/texSize); \n" + " mediump vec2 Coords11 = floor(tcData[3] * lod_scale); \n" + " mediump float offset11 = offset + width * Coords11.t + Coords11.s; \n" + " mediump float Y11 = floor(offset11 / mipmapTileWidth); \n" + " lowp vec4 c11 = texture2D(tex, (vec2(offset11 - mipmapTileWidth * Y11, Y11) + 0.5)/texSize); \n" + ; + static const std::string strBillinear3PointEndGles2 = + " lowp vec4 c0 = c00 + tcData[4].s*(c10-c00) + tcData[4].t*(c01-c00); \n" + " lowp vec4 c1 = c11 + (1.0-tcData[4].s)*(c01-c11) + (1.0-tcData[4].t)*(c10-c11); \n" + " lowp float bottomRightTri = step(1.0, tcData[4].s + tcData[4].t); \n" + " return c0 + bottomRightTri * (c1-c0); \n" + " return c00; \n" + "} \n" + ; + static const std::string strBillinearStandardEndGles2 = + " lowp vec4 c0 = c00 + tcData[4].s * (c10-c00); \n" + " lowp vec4 c1 = c01 + tcData[4].s * (c11-c01); \n" + " return c0 + tcData[4].t * (c1-c0); \n" + " return c00; \n" + "} \n" + ; + + if (config.texture.bilinearMode == BILINEAR_3POINT) { + m_part = strReadTex0; + m_part += strBillinear3PointEndGles2; + m_part += strReadTex1; + m_part += strBillinear3PointEndGles2; + } else { + m_part = strReadTex0; + m_part += strBillinearStandardEndGles2; + m_part += strReadTex1; + m_part += strBillinearStandardEndGles2; + } + + m_part += + "uniform lowp int uEnableLod; \n" + "uniform mediump float uMinLod; \n" + "uniform lowp int uMaxTile; \n" + "uniform lowp int uTextureDetail; \n" + " \n" + "mediump float mipmap(out lowp vec4 readtex0, out lowp vec4 readtex1) { \n" + ; + + if (config.generalEmulation.enableLOD == 0) { + m_part += + " mediump float lod = 1.0; \n" + ; + } else { + m_part += + " mediump vec2 dx = abs(dFdx(vLodTexCoord)) * uScreenScale; \n" + " mediump vec2 dy = abs(dFdy(vLodTexCoord)) * uScreenScale; \n" + " mediump float lod = max(max(dx.x, dx.y), max(dy.x, dy.y)); \n" + ; + } + m_part += + "#define MIN(x, y) y < x ? y : x \n" + "#define MAX(x, y) x < y ? y : x \n" + " lowp int lod_max_tile = uTextureDetail != 2 ? 7 : 6; \n" + " lowp int max_tile = MIN(lod_max_tile, uMaxTile); \n" + " mediump float min_lod = uTextureDetail != 0 ? uMinLod : 1.0; \n" + " mediump float max_lod = pow(2.0, float(max_tile)) - 1.0 / 32.0; \n" + " mediump float lod_clamp = min(max(lod, min_lod), max_lod); \n" + // Simulate clamp function, needed for GLES 2.0 and integer types + " mediump int lod_clamp_int = int(log2(lod_clamp)); \n" + " mediump int lod_clamp_max = MAX(lod_clamp_int, 0); \n" + " lowp int lod_tile = MIN(lod_clamp_max, max_tile); \n" + " lowp int tile0 = 0; \n" + " lowp int tile1 = 1; \n" + " if (uEnableLod != 0) { \n" + " if (lod_clamp < 1.0 && uTextureDetail == 0) { \n" + " tile0 = 0; \n" + " tile1 = 0; \n" + " } else if (lod_clamp >= 1.0 && uTextureDetail == 2) { \n" + " tile0 = lod_tile + 1; \n" + " tile1 = lod_tile + 2; \n" + " } else { \n" + " tile0 = lod_tile; \n" + " tile1 = lod_tile + 1; \n" + " } \n" + " } \n" + " mediump float lod_frac = lod_clamp / pow(2.0, float(lod_tile)); \n" + " if (uTextureDetail == 1 || lod_clamp >= 1.0) { \n" + " lod_frac = clamp(lod_frac - 1.0, -1.0, 1.0); \n" + " } \n" + " \n" + " if (tile0 == 0) \n" + " readtex0 = TextureMipMap0(uTex0, tcData0); \n" + " else if (uEnableLod == 0 || uMaxTile == 1) \n" + " readtex0 = TextureMipMap0(uTex1, tcData1); \n" + " else readtex0 = TextureMipMap1(uTex1, tcData1, float(tile0 - 1)); \n" + " if (tile1 == 0) \n" + " readtex1 = TextureMipMap0(uTex0, tcData0); \n" + " else if (uEnableLod == 0 || uMaxTile == 1) \n" + " readtex1 = TextureMipMap0(uTex1, tcData1); \n" + " else readtex1 = TextureMipMap1(uTex1, tcData1, float(tile1 - 1)); \n" + " return lod_frac; \n" + "} \n" + ; + } + else { + static const std::string strReadTex0 = + "#define READ_TEX0_MIPMAP(name, tex, tcData) \\\n" + "{ \\\n" + " lowp vec4 c00 = texelFetch(tex, ivec2(tcData[0]), 0); \\\n" + " lowp vec4 c01 = texelFetch(tex, ivec2(tcData[1]), 0); \\\n" + " lowp vec4 c10 = texelFetch(tex, ivec2(tcData[2]), 0); \\\n" + " lowp vec4 c11 = texelFetch(tex, ivec2(tcData[3]), 0); \\\n" + ; + static const std::string strReadTex1 = + "#define READ_TEX1_MIPMAP(name, tex, tcData, tile) \\\n" + "{ \\\n" + // Fetch from texture atlas + // First 8 texels contain info about tile size and offset, 1 texel per tile + " mediump vec4 texWdthAndOff0 = 255.0 * texelFetch(tex, ivec2(0, 0), 0); \\\n" + " mediump vec4 texWdthAndOff = 255.0 * texelFetch(tex, ivec2(int(tile), 0), 0); \\\n" + " mediump vec2 lod_scale = texWdthAndOff.ba / texWdthAndOff0.ba; \\\n" + " mediump int offset = int(texWdthAndOff.r) + int(texWdthAndOff.g) * 256; \\\n" + " mediump int width = int(texWdthAndOff.b); \\\n" + " mediump ivec2 iCoords00 = ivec2(tcData[0] * lod_scale); \\\n" + " mediump int offset00 = offset + width * iCoords00.t + iCoords00.s; \\\n" + " mediump int Y00 = offset00/mipmapTileWidth; \\\n" + " lowp vec4 c00 = texelFetch(tex, ivec2(offset00 - mipmapTileWidth * Y00, Y00), 0); \\\n" + " mediump ivec2 iCoords01 = ivec2(tcData[1] * lod_scale); \\\n" + " mediump int offset01 = offset + width * iCoords01.t + iCoords01.s; \\\n" + " mediump int Y01 = offset01/mipmapTileWidth; \\\n" + " lowp vec4 c01 = texelFetch(tex, ivec2(offset01 - mipmapTileWidth * Y01, Y01), 0); \\\n" + " mediump ivec2 iCoords10 = ivec2(tcData[2] * lod_scale); \\\n" + " mediump int offset10 = offset + width * iCoords10.t + iCoords10.s; \\\n" + " mediump int Y10 = offset10/mipmapTileWidth; \\\n" + " lowp vec4 c10 = texelFetch(tex, ivec2(offset10 - mipmapTileWidth * Y10, Y10), 0); \\\n" + " mediump ivec2 iCoords11 = ivec2(tcData[3] * lod_scale); \\\n" + " mediump int offset11 = offset + width * iCoords11.t + iCoords11.s; \\\n" + " mediump int Y11 = offset11/mipmapTileWidth; \\\n" + " lowp vec4 c11 = texelFetch(tex, ivec2(offset11 - mipmapTileWidth * Y11, Y11), 0); \\\n" + ; + static const std::string strBillinear3PointEnd = + " lowp vec4 c0 = c00 + tcData[4].s*(c10-c00) + tcData[4].t*(c01-c00); \\\n" + " lowp vec4 c1 = c11 + (1.0-tcData[4].s)*(c01-c11) + (1.0-tcData[4].t)*(c10-c11); \\\n" + " lowp float bottomRightTri = step(1.0, tcData[4].s + tcData[4].t); \\\n" + " name = c0 + bottomRightTri * (c1-c0); \\\n" + "} \n" + ; + static const std::string strBillinearStandardEnd = + " lowp vec4 c0 = c00 + tcData[4].s * (c10-c00); \\\n" + " lowp vec4 c1 = c01 + tcData[4].s * (c11-c01); \\\n" + " name = c0 + tcData[4].t * (c1-c0); \\\n" + "} \n" + ; + if (config.texture.bilinearMode == BILINEAR_3POINT) { + m_part = strReadTex0; + m_part += strBillinear3PointEnd; + m_part += strReadTex1; + m_part += strBillinear3PointEnd; + } else { + m_part = strReadTex0; + m_part += strBillinearStandardEnd; + m_part += strReadTex1; + m_part += strBillinearStandardEnd; + } + m_part += + "uniform lowp int uEnableLod; \n" + "uniform mediump float uMinLod; \n" + "uniform lowp int uMaxTile; \n" + "uniform lowp int uTextureDetail; \n" + " \n" + "mediump float mipmap(out lowp vec4 readtex0, out lowp vec4 readtex1) { \n" + ; + if (config.generalEmulation.enableLOD == 0) { + m_part += + " mediump float lod = 1.0; \n" + ; + } else { + m_part += + " mediump vec2 dx = abs(dFdx(vLodTexCoord)) * uScreenScale; \n" + " mediump vec2 dy = abs(dFdy(vLodTexCoord)) * uScreenScale; \n" + " mediump float lod = max(max(dx.x, dx.y), max(dy.x, dy.y)); \n" + ; + } + m_part += + " lowp int max_tile = min(uTextureDetail != 2 ? 7 : 6, uMaxTile); \n" + " mediump float min_lod = uTextureDetail != 0 ? uMinLod : 1.0; \n" + " mediump float max_lod = pow(2.0, float(max_tile)) - 1.0 / 32.0; \n" + " mediump float lod_clamp = min(max(lod, min_lod), max_lod); \n" + " lowp int lod_tile = clamp(int(log2(lod_clamp)), 0 , max_tile); \n" + " lowp int tile0 = 0; \n" + " lowp int tile1 = 1; \n" + " if (uEnableLod != 0) { \n" + " if (lod_clamp < 1.0 && uTextureDetail == 0) { \n" + " tile0 = 0; \n" + " tile1 = 0; \n" + " } else if (lod_clamp >= 1.0 && uTextureDetail == 2) { \n" + " tile0 = lod_tile + 1; \n" + " tile1 = lod_tile + 2; \n" + " } else { \n" + " tile0 = lod_tile; \n" + " tile1 = lod_tile + 1; \n" + " } \n" + " } \n" + " mediump float lod_frac = lod_clamp / pow(2.0, float(lod_tile)); \n" + " if (uTextureDetail == 1 || lod_clamp >= 1.0) { \n" + " lod_frac = clamp(lod_frac - 1.0, -1.0, 1.0); \n" + " } \n" + " \n" + " if(tile0 == 0) {READ_TEX0_MIPMAP(readtex0, uTex0, tcData0);} \n" + " else if (uEnableLod == 0 || uMaxTile == 1) {READ_TEX0_MIPMAP(readtex0, uTex1, tcData1);}\n" + " else {READ_TEX1_MIPMAP(readtex0, uTex1, tcData1, tile0 - 1);} \n" + " if(tile1 == 0) {READ_TEX0_MIPMAP(readtex1, uTex0, tcData0);} \n" + " else if (uEnableLod == 0 || uMaxTile == 1) {READ_TEX0_MIPMAP(readtex1, uTex1, tcData1);}\n" + " else {READ_TEX1_MIPMAP(readtex1, uTex1, tcData1, tile1 - 1);} \n" + " return lod_frac; \n" + "} \n" + ; + } + } +}; + +class ShaderReadtex : public ShaderPart +{ +public: + ShaderReadtex(const opengl::GLInfo & _glinfo) : m_glinfo(_glinfo) + { + } + + void write(std::stringstream & shader) const override + { + std::string shaderPart; + + if (m_glinfo.isGLES2) { + shaderPart += + "lowp vec4 TextureNearest(in sampler2D tex, in highp vec2 tcData[5]) \n" + "{ \n" + " mediump vec2 texSize; \n" + " if (nCurrentTile == 0) \n" + " texSize = uTextureSize[0]; \n" + " else \n" + " texSize = uTextureSize[1]; \n" + " return texture2D(tex, (tcData[0] + 0.5) / texSize); \n" + " } \n" + ; + if (CombinerProgramBuilder::s_textureConvert.useYUVCoversion()) + shaderPart += + "lowp vec4 YUV_Convert(in sampler2D tex, in highp vec2 tcData[5], in lowp int convert, in lowp int format, in lowp vec4 prev) \n" + "{ \n" + " lowp vec4 texColor; \n" + " if (convert != 0) texColor = prev; \n" + " else texColor = TextureNearest(tex, tcData); \n" + " mediump ivec4 icolor = ivec4(texColor*255.0); \n" + " if (format == 1) \n" + " icolor.rg -= 128; \n" + " mediump ivec4 iconvert; \n" + " iconvert.r = icolor.b + (uConvertParams[0]*icolor.g + 128)/256; \n" + " iconvert.g = icolor.b + (uConvertParams[1]*icolor.r + uConvertParams[2]*icolor.g + 128)/256; \n" + " iconvert.b = icolor.b + (uConvertParams[3]*icolor.r + 128)/256; \n" + " iconvert.a = icolor.b; \n" + " return vec4(iconvert)/255.0; \n" + " } \n" + ; + if (CombinerProgramBuilder::s_textureConvert.useTextureFiltering()) { + if (config.texture.bilinearMode == BILINEAR_3POINT) { + shaderPart += + // 3 point texture filtering. + // Original author: ArthurCarvalho + // GLSL implementation: twinaphex, mupen64plus-libretro project. + "lowp vec4 TextureFilter(in sampler2D tex, in highp vec2 tcData[5]) \n" + "{ \n" + " mediump vec2 texSize; \n" + " if (nCurrentTile == 0) \n" + " texSize = uTextureSize[0]; \n" + " else \n" + " texSize = uTextureSize[1]; \n" + " lowp float bottomRightTri = step(1.0, tcData[4].s + tcData[4].t); \n" + " lowp vec4 c00 = texture2D(tex, (tcData[0] + 0.5)/texSize); \n" + " lowp vec4 c01 = texture2D(tex, (tcData[1] + 0.5)/texSize); \n" + " lowp vec4 c10 = texture2D(tex, (tcData[2] + 0.5)/texSize); \n" + " lowp vec4 c11 = texture2D(tex, (tcData[3] + 0.5)/texSize); \n" + " lowp vec4 c0 = c00 + tcData[4].s*(c10-c00) + tcData[4].t*(c01-c00); \n" + " lowp vec4 c1 = c11 + (1.0-tcData[4].s)*(c01-c11) + (1.0-tcData[4].t)*(c10-c11); \n" + " return c0 + bottomRightTri * (c1-c0); \n" + " } \n" + ; + } else { + shaderPart += + // bilinear filtering. + "lowp vec4 TextureFilter(in sampler2D tex, in highp vec2 tcData[5]) \n" + "{ \n" + " mediump vec2 texSize; \n" + " if (nCurrentTile == 0) \n" + " texSize = uTextureSize[0]; \n" + " else \n" + " texSize = uTextureSize[1]; \n" + " lowp vec4 c00 = texture2D(tex, (tcData[0] + 0.5)/texSize); \n" + " lowp vec4 c01 = texture2D(tex, (tcData[1] + 0.5)/texSize); \n" + " lowp vec4 c10 = texture2D(tex, (tcData[2] + 0.5)/texSize); \n" + " lowp vec4 c11 = texture2D(tex, (tcData[3] + 0.5)/texSize); \n" + " lowp vec4 c0 = c00 + tcData[4].s * (c10-c00); \n" + " lowp vec4 c1 = c01 + tcData[4].s * (c11-c01); \n" + " return c0 + tcData[4].t * (c1-c0); \n" + " } \n" + ; + } + shaderPart += + "lowp vec4 readTex(in sampler2D tex, in highp vec2 tcData[5], in lowp int fbMonochrome, in lowp int fbFixedAlpha) \n" + "{ \n" + " lowp vec4 texColor; \n" + " if (uTextureFilterMode == 0) texColor = TextureNearest(tex, tcData); \n" + " else texColor = TextureFilter(tex, tcData); \n" + " if (fbMonochrome == 1) texColor = vec4(texColor.r); \n" + " else if (fbMonochrome == 2) \n" + " texColor.rgb = vec3(dot(vec3(0.2126, 0.7152, 0.0722), texColor.rgb)); \n" + " if (fbFixedAlpha == 1) texColor.a = 0.825; \n" + " return texColor; \n" + "} \n" + ; + } + } else { + if (config.video.multisampling > 0 && CombinerProgramBuilder::s_textureConvert.useTextureFiltering()) { + shaderPart = + "uniform lowp int uMSAASamples; \n" + "lowp vec4 sampleMS(in lowp sampler2DMS mstex, in mediump ivec2 ipos) \n" + "{ \n" + " lowp vec4 texel = vec4(0.0); \n" + " for (int i = 0; i < uMSAASamples; ++i) \n" + " texel += texelFetch(mstex, ipos, i); \n" + " return texel / float(uMSAASamples); \n" + "} \n" + " \n" + "lowp vec4 readTexMS(in lowp sampler2DMS mstex, in highp vec2 tcData[5], in lowp int fbMonochrome, in lowp int fbFixedAlpha) \n" + "{ \n" + " mediump ivec2 itexCoord; \n" + " if (fbMonochrome == 3) { \n" + " itexCoord = ivec2(gl_FragCoord.xy); \n" + " } else { \n" + " itexCoord = ivec2(tcData[0]); \n" + " } \n" + " lowp vec4 texColor = sampleMS(mstex, itexCoord); \n" + " if (fbMonochrome == 1) texColor = vec4(texColor.r); \n" + " else if (fbMonochrome == 2) \n" + " texColor.rgb = vec3(dot(vec3(0.2126, 0.7152, 0.0722), texColor.rgb)); \n" + " else if (fbMonochrome == 3) { \n" + " texColor.rgb = vec3(dot(vec3(0.2126, 0.7152, 0.0722), texColor.rgb)); \n" + " texColor.a = 0.0; \n" + " } \n" + " if (fbFixedAlpha == 1) texColor.a = 0.825; \n" + " return texColor; \n" + "} \n" + ; + } + } + + shader << shaderPart; + } + +private: + const opengl::GLInfo& m_glinfo; +}; + +class ShaderReadtexCopyMode : public ShaderPart +{ +public: + ShaderReadtexCopyMode(const opengl::GLInfo & _glinfo) + { + if (_glinfo.isGLES2) { + m_part = + "lowp vec4 TextureNearest(in sampler2D tex, in highp vec2 tcData[5]) \n" + "{ \n" + " mediump vec2 texSize; \n" + " if (nCurrentTile == 0) \n" + " texSize = uTextureSize[0]; \n" + " else \n" + " texSize = uTextureSize[1]; \n" + " return texture2D(tex, (tcData[0] + 0.5) / texSize); \n" + " } \n" + "lowp vec4 readTex(in sampler2D tex, in highp vec2 tcData[5], in lowp int fbMonochrome, in lowp int fbFixedAlpha) \n" + "{ \n" + " lowp vec4 texColor = TextureNearest(tex, tcData); \n" + " if (fbMonochrome == 1) texColor = vec4(texColor.r); \n" + " else if (fbMonochrome == 2) \n" + " texColor.rgb = vec3(dot(vec3(0.2126, 0.7152, 0.0722), texColor.rgb)); \n" + " if (fbFixedAlpha == 1) texColor.a = 0.825; \n" + " return texColor; \n" + "} \n" + ; + } else { + if (config.video.multisampling > 0) { + m_part = + "uniform lowp int uMSAASamples; \n" + "lowp vec4 sampleMS(in lowp sampler2DMS mstex, in mediump ivec2 ipos) \n" + "{ \n" + " lowp vec4 texel = vec4(0.0); \n" + " for (int i = 0; i < uMSAASamples; ++i) \n" + " texel += texelFetch(mstex, ipos, i); \n" + " return texel / float(uMSAASamples); \n" + "} \n" + " \n" + "lowp vec4 readTexMS(in lowp sampler2DMS mstex, in highp vec2 tcData[5], in lowp int fbMonochrome, in lowp int fbFixedAlpha) \n" + "{ \n" + " mediump ivec2 itexCoord; \n" + " if (fbMonochrome == 3) { \n" + " itexCoord = ivec2(gl_FragCoord.xy); \n" + " } else { \n" + " itexCoord = ivec2(tcData[0]); \n" + " } \n" + " lowp vec4 texColor = sampleMS(mstex, itexCoord); \n" + " if (fbMonochrome == 1) texColor = vec4(texColor.r); \n" + " else if (fbMonochrome == 2) \n" + " texColor.rgb = vec3(dot(vec3(0.2126, 0.7152, 0.0722), texColor.rgb)); \n" + " else if (fbMonochrome == 3) { \n" + " texColor.rgb = vec3(dot(vec3(0.2126, 0.7152, 0.0722), texColor.rgb)); \n" + " texColor.a = 0.0; \n" + " } \n" + " if (fbFixedAlpha == 1) texColor.a = 0.825; \n" + " return texColor; \n" + "} \n" + ; + } + } + } +}; + +class ShaderTextureEngine : public ShaderPart +{ +public: + ShaderTextureEngine(const opengl::GLInfo _glinfo) { + m_part = + "highp vec2 clampWrapMirror(in highp vec2 vTexCoord, in highp vec2 vWrap, \n" + " in highp vec2 vClamp, in lowp vec2 vWrapEn, in lowp vec2 vClampEn, in lowp vec2 vMirrorEn) \n" + "{ \n" + " highp vec2 texCoord = vTexCoord; \n" + " highp vec2 clampedCoord = clamp(texCoord, vec2(0.0), vClamp); \n" + " texCoord += vClampEn*(clampedCoord-texCoord); \n" + " lowp vec2 needMirror = step(vWrap, mod(texCoord, 2.0*vWrap)); \n" + " highp vec2 invertedCoord = mod(-texCoord-vec2(1.0), vWrap); \n" + " texCoord += vMirrorEn*needMirror*(invertedCoord-texCoord); \n" + " highp vec2 wrappedCoord = mod(texCoord,vWrap); \n" + " texCoord += vWrapEn*(wrappedCoord-texCoord); \n" + " return texCoord; \n" + "} \n" + + "highp vec2 wrap2D(in highp vec2 tc, in highp vec2 size) \n" + "{ \n" + " highp float divs = floor(tc.s / size.s); \n" + " highp float divt = floor((tc.t + divs) / size.t); \n" + " return vec2(tc.s - divs * size.s, tc.t + divs - divt*size.t); \n" + "} \n" + + "void textureEngine0(in highp vec2 texCoord, out highp vec2 tcData[5]) \n" + "{ \n" + " highp vec2 tileCoord = (WRAP(texCoord * uShiftScale[0] - uTexOffset[0], -1024.0, 1024.0));\n" + " tileCoord = (tileCoord + uBilinearOffset) * uHDRatio[0] - uBilinearOffset; \n" + " mediump vec2 intPart = floor(tileCoord); \n" + " highp vec2 tc00 = clampWrapMirror(intPart, uTexWrap[0], uTexClamp[0], uTexWrapEn[0], uTexClampEn[0], uTexMirrorEn[0]); \n" + " highp vec2 tc11 = clampWrapMirror(intPart + vec2(1.0,1.0), uTexWrap[0], uTexClamp[0], uTexWrapEn[0], uTexClampEn[0], uTexMirrorEn[0]); \n" + " tcData[0] = wrap2D(tc00, uTexSize[0]) + uCacheOffset[0]; \n" + " tcData[3] = wrap2D(tc11, uTexSize[0]) + uCacheOffset[0]; \n" + " tcData[1] = vec2(tcData[0].s, tcData[3].t); \n" + " tcData[2] = vec2(tcData[3].s, tcData[0].t); \n" + " tcData[4] = tileCoord - intPart; \n" + "} \n" + + "void textureEngine1(in highp vec2 texCoord, out highp vec2 tcData[5]) \n" + "{ \n" + " highp vec2 tileCoord = (WRAP(texCoord * uShiftScale[1] - uTexOffset[1], -1024.0, 1024.0)); \n" + " tileCoord = (tileCoord + uBilinearOffset) * uHDRatio[1] - uBilinearOffset; \n" + " mediump vec2 intPart = floor(tileCoord); \n" + " highp vec2 tc00 = clampWrapMirror(intPart, uTexWrap[1], uTexClamp[1], uTexWrapEn[1], uTexClampEn[1], uTexMirrorEn[1]); \n" + " highp vec2 tc11 = clampWrapMirror(intPart + vec2(1.0,1.0), uTexWrap[1], uTexClamp[1], uTexWrapEn[1], uTexClampEn[1], uTexMirrorEn[1]); \n" + " tcData[0] = wrap2D(tc00, uTexSize[1]) + uCacheOffset[1]; \n" + " tcData[3] = wrap2D(tc11, uTexSize[1]) + uCacheOffset[1]; \n" + " tcData[1] = vec2(tcData[0].s, tcData[3].t); \n" + " tcData[2] = vec2(tcData[3].s, tcData[0].t); \n" + " tcData[4] = tileCoord - intPart; \n" + "} \n" + + ; + } +}; + +class ShaderFragmentTextureEngineTex0 : public ShaderPart { +public: + ShaderFragmentTextureEngineTex0(const opengl::GLInfo _glinfo) + { + m_part = + "textureEngine0(mTexCoord0, tcData0); \n" + ; + } +}; + +class ShaderFragmentTextureEngineTex1 : public ShaderPart { +public: + ShaderFragmentTextureEngineTex1(const opengl::GLInfo _glinfo) + { + m_part = + "textureEngine1(mTexCoord1, tcData1); \n" + ; + } +}; + +CombinerProgramBuilderAccurate::CombinerProgramBuilderAccurate(const opengl::GLInfo & _glinfo, opengl::CachedUseProgram * _useProgram) +: CombinerProgramBuilderCommon(_glinfo, _useProgram, std::make_unique(_glinfo), + std::make_unique(_glinfo)) +, m_fragmentGlobalVariablesTex(new ShaderFragmentGlobalVariablesTex(_glinfo)) +, m_fragmentHeaderTextureEngine(new ShaderFragmentHeaderTextureEngine(_glinfo)) +, m_fragmentHeaderReadMSTex(new ShaderFragmentHeaderReadMSTex(_glinfo)) +, m_fragmentHeaderReadTex(new ShaderFragmentHeaderReadTex(_glinfo)) +, m_fragmentHeaderReadTexCopyMode(new ShaderFragmentHeaderReadTexCopyMode(_glinfo)) +, m_fragmentReadTex0(new ShaderFragmentReadTex0(_glinfo)) +, m_fragmentReadTex1(new ShaderFragmentReadTex1(_glinfo)) +, m_fragmentTextureEngineTex0(new ShaderFragmentTextureEngineTex0(_glinfo)) +, m_fragmentTextureEngineTex1(new ShaderFragmentTextureEngineTex1(_glinfo)) +, m_fragmentReadTexCopyMode(new ShaderFragmentReadTexCopyMode(_glinfo)) +, m_shaderMipmap(new ShaderMipmap(_glinfo)) +, m_shaderReadtex(new ShaderReadtex(_glinfo)) +, m_shaderReadtexCopyMode(new ShaderReadtexCopyMode(_glinfo)) +, m_shaderTextureEngine(new ShaderTextureEngine(_glinfo)) +{ +} + +void CombinerProgramBuilderAccurate::_writeFragmentGlobalVariablesTex(std::stringstream& ssShader) const +{ + m_fragmentGlobalVariablesTex->write(ssShader); +} + +void CombinerProgramBuilderAccurate::_writeFragmentHeaderReadMSTex(std::stringstream& ssShader) const +{ + m_fragmentHeaderReadMSTex->write(ssShader); +} + +void CombinerProgramBuilderAccurate::_writeFragmentHeaderReadTex(std::stringstream& ssShader) const +{ + m_fragmentHeaderReadTex->write(ssShader); +} + +void CombinerProgramBuilderAccurate::_writeFragmentHeaderReadTexCopyMode(std::stringstream& ssShader) const +{ + m_fragmentHeaderReadTexCopyMode->write(ssShader); +} + +void CombinerProgramBuilderAccurate::_writeFragmentHeaderClampWrapMirrorEngine(std::stringstream& ssShader) const +{ + m_fragmentHeaderTextureEngine->write(ssShader); +} + +void CombinerProgramBuilderAccurate::_writeFragmentClampWrapMirrorEngineTex0(std::stringstream& ssShader) const +{ + m_fragmentTextureEngineTex0->write(ssShader); +} + +void CombinerProgramBuilderAccurate::_writeFragmentClampWrapMirrorEngineTex1(std::stringstream& ssShader) const +{ + m_fragmentTextureEngineTex1->write(ssShader); +} + +void CombinerProgramBuilderAccurate::_writeFragmentReadTex0(std::stringstream& ssShader) const +{ + m_fragmentReadTex0->write(ssShader); +} + +void CombinerProgramBuilderAccurate::_writeFragmentReadTex1(std::stringstream& ssShader) const +{ + m_fragmentReadTex1->write(ssShader); +} + +void CombinerProgramBuilderAccurate::_writeFragmentReadTexCopyMode(std::stringstream& ssShader) const +{ + m_fragmentReadTexCopyMode->write(ssShader); +} + +void CombinerProgramBuilderAccurate::_writeShaderClampWrapMirrorEngine(std::stringstream& ssShader) const +{ + m_shaderTextureEngine->write(ssShader); +} + +void CombinerProgramBuilderAccurate::_writeShaderMipmap(std::stringstream& ssShader) const +{ + m_shaderMipmap->write(ssShader); +} + +void CombinerProgramBuilderAccurate::_writeShaderReadtex(std::stringstream& ssShader) const +{ + m_shaderReadtex->write(ssShader); +} + +void CombinerProgramBuilderAccurate::_writeShaderReadtexCopyMode(std::stringstream& ssShader) const +{ + m_shaderReadtexCopyMode->write(ssShader); +} + +} diff --git a/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilderAccurate.h b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilderAccurate.h new file mode 100644 index 00000000..bb12510d --- /dev/null +++ b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilderAccurate.h @@ -0,0 +1,46 @@ +#pragma once +#include + +namespace glsl { + +class CombinerProgramUniformFactory; + +class CombinerProgramBuilderAccurate : public glsl::CombinerProgramBuilderCommon +{ +public: + CombinerProgramBuilderAccurate(const opengl::GLInfo & _glinfo, opengl::CachedUseProgram * _useProgram); + +private: + void _writeFragmentGlobalVariablesTex(std::stringstream& ssShader) const override; + void _writeFragmentHeaderReadMSTex(std::stringstream& ssShader) const override; + void _writeFragmentHeaderReadTex(std::stringstream& ssShader) const override; + void _writeFragmentHeaderReadTexCopyMode(std::stringstream& ssShader) const override; + void _writeFragmentHeaderClampWrapMirrorEngine(std::stringstream& ssShader) const override; + void _writeFragmentClampWrapMirrorEngineTex0(std::stringstream& ssShader) const override; + void _writeFragmentClampWrapMirrorEngineTex1(std::stringstream& ssShader) const override; + void _writeFragmentReadTex0(std::stringstream& ssShader) const override; + void _writeFragmentReadTex1(std::stringstream& ssShader) const override; + void _writeFragmentReadTexCopyMode(std::stringstream& ssShader) const override; + void _writeShaderClampWrapMirrorEngine(std::stringstream& ssShader) const override; + void _writeShaderMipmap(std::stringstream& ssShader) const override; + void _writeShaderReadtex(std::stringstream& ssShader) const override; + void _writeShaderReadtexCopyMode(std::stringstream& ssShader) const override; + + ShaderPartPtr m_fragmentGlobalVariablesTex; + ShaderPartPtr m_fragmentHeaderTextureEngine; + ShaderPartPtr m_fragmentHeaderReadMSTex; + ShaderPartPtr m_fragmentHeaderReadTex; + ShaderPartPtr m_fragmentHeaderReadTexCopyMode; + ShaderPartPtr m_fragmentReadTexCopyMode; + ShaderPartPtr m_fragmentReadTex0; + ShaderPartPtr m_fragmentReadTex1; + ShaderPartPtr m_shaderMipmap; + ShaderPartPtr m_shaderReadtex; + ShaderPartPtr m_shaderReadtexCopyMode; + ShaderPartPtr m_shaderTextureEngine; + ShaderPartPtr m_fragmentTextureEngineTex0; + ShaderPartPtr m_fragmentTextureEngineTex1; +}; + +} + diff --git a/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilderCommon.cpp b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilderCommon.cpp new file mode 100644 index 00000000..a2286793 --- /dev/null +++ b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilderCommon.cpp @@ -0,0 +1,1681 @@ +#include // for setprecision +#include +#include +#include +#include "glsl_Utils.h" +#include "glsl_CombinerInputs.h" +#include "glsl_CombinerProgramImpl.h" +#include "glsl_CombinerProgramBuilderCommon.h" +#include "glsl_CombinerProgramUniformFactory.h" +#include "GraphicsDrawer.h" + +namespace glsl { + +/*---------------ShaderParts-------------*/ + +class VertexShaderHeader : public ShaderPart +{ +public: + VertexShaderHeader(const opengl::GLInfo & _glinfo) + { + if (_glinfo.isGLES2) { + m_part = "#version 100 \n"; + m_part += + "#if (__VERSION__ > 120) \n" + "# define IN in \n" + "# define OUT out \n" + "#else \n" + "# define IN attribute \n" + "# define OUT varying \n" + "#ifndef GL_FRAGMENT_PRECISION_HIGH \n" + "# define highp mediump \n" + "#endif \n" + "#endif // __VERSION \n" + ; + } + else if (_glinfo.isGLESX) { + std::stringstream ss; + ss << "#version " << Utils::to_string(_glinfo.majorVersion) << Utils::to_string(_glinfo.minorVersion) << "0 es " << std::endl; + ss << "# define IN in" << std::endl << "# define OUT out" << std::endl; + if (_glinfo.noPerspective) { + ss << "#extension GL_NV_shader_noperspective_interpolation : enable" << std::endl + << "noperspective OUT highp float vZCoord;" << std::endl + << "uniform lowp int uClampMode;" << std::endl; + } + m_part = ss.str(); + } + else { + std::stringstream ss; + ss << "#version " << Utils::to_string(_glinfo.majorVersion) << Utils::to_string(_glinfo.minorVersion) << "0 core " << std::endl; + ss << "# define IN in" << std::endl << "# define OUT out" << std::endl; + m_part = ss.str(); + } + m_part += "uniform lowp vec2 uVertexOffset; \n"; + std::stringstream ss; + ss << "const lowp float screenSizeDims = " << std::setprecision(1) << std::fixed << SCREEN_SIZE_DIM << ";" << std::endl; + m_part += ss.str(); + } +}; + +class VertexShaderTriangle : public ShaderPart +{ +public: + VertexShaderTriangle(const opengl::GLInfo & _glinfo) + { + m_part = + "IN highp vec4 aPosition; \n" + "IN lowp vec4 aColor; \n" + "IN lowp float aNumLights; \n" + "IN highp vec4 aModify; \n" + "IN highp vec2 aBaryCoords; \n" + " \n" + "uniform lowp int uFogUsage; \n" + "uniform mediump vec2 uFogScale; \n" + "uniform mediump vec2 uScreenCoordsScale; \n" + "uniform mediump vec2 uVTrans; \n" + "uniform mediump vec2 uVScale; \n" + "uniform mediump vec2 uAdjustTrans; \n" + "uniform mediump vec2 uAdjustScale; \n" + " \n" + "OUT lowp float vNumLights; \n" + "OUT lowp vec4 vShadeColor; \n" + "OUT highp vec4 vBaryCoords; \n" + ; + if (!_glinfo.isGLESX || _glinfo.noPerspective) + m_part += "noperspective OUT lowp vec4 vShadeColorNoperspective;\n"; + else + m_part += "OUT lowp vec4 vShadeColorNoperspective; \n"; + m_part += + " \n" + "void main() \n" + "{ \n" + " gl_Position = aPosition; \n" + " vShadeColor = aColor; \n" + " vNumLights = aNumLights; \n" + " if ((aModify[0]) != 0.0) { \n" + " gl_Position.xy *= gl_Position.w; \n" + " } \n" + " else { \n" + " gl_Position.xy = gl_Position.xy * uVScale.xy + uVTrans.xy * gl_Position.ww; \n" + " gl_Position.xy = floor(gl_Position.xy * vec2(4.0)) * vec2(0.25); \n" + " gl_Position.xy = gl_Position.xy * uAdjustScale + gl_Position.ww * uAdjustTrans; \n" + " } \n" + " if ((aModify[1]) != 0.0) \n" + " gl_Position.z *= gl_Position.w; \n" + " if ((aModify[3]) != 0.0) \n" + " vNumLights = 0.0; \n" + " if (uFogUsage > 0) { \n" + " lowp float fp; \n" + " if (aPosition.z < -aPosition.w && aModify[1] == 0.0) \n" + " fp = -uFogScale.s + uFogScale.t; \n" + " else \n" + " fp = aPosition.z/aPosition.w*uFogScale.s + uFogScale.t; \n" + " fp = clamp(fp, 0.0, 1.0); \n" + " if (uFogUsage == 1) \n" + " vShadeColor.a = fp; \n" + " else \n" + " vShadeColor.rgb = vec3(fp); \n" + " } \n" + " vBaryCoords = vec4(aBaryCoords, 1.0 - aBaryCoords.x - aBaryCoords.y, 0.5); \n" + " vShadeColorNoperspective = vShadeColor; \n" + ; + } +}; + +class VertexShaderTexturedRect : public ShaderPart +{ +public: + VertexShaderTexturedRect(const opengl::GLInfo & _glinfo) + { + m_part = + "IN highp vec4 aRectPosition; \n" + "IN highp vec2 aTexCoord0; \n" + "IN highp vec2 aTexCoord1; \n" + "IN highp vec2 aBaryCoords; \n" + " \n" + "OUT highp vec2 vTexCoord0; \n" + "OUT highp vec2 vTexCoord1; \n" + "OUT lowp vec4 vShadeColor; \n" + "OUT highp vec4 vBaryCoords;" + ; + if (!_glinfo.isGLESX || _glinfo.noPerspective) + m_part += "noperspective OUT lowp vec4 vShadeColorNoperspective;\n"; + else + m_part += "OUT lowp vec4 vShadeColorNoperspective; \n"; + m_part += + "uniform lowp vec4 uRectColor; \n" + "void main() \n" + "{ \n" + " gl_Position = aRectPosition; \n" + " vShadeColor = uRectColor; \n" + " vShadeColorNoperspective = uRectColor; \n" + " vTexCoord0 = aTexCoord0; \n" + " vTexCoord1 = aTexCoord1; \n" + " vBaryCoords = vec4(aBaryCoords, vec2(1.0) - aBaryCoords); \n" + ; + } +}; + +class VertexShaderRect : public ShaderPart +{ +public: + VertexShaderRect(const opengl::GLInfo & _glinfo) + { + m_part = + "IN highp vec4 aRectPosition; \n" + "IN highp vec2 aBaryCoords; \n" + " \n" + "OUT lowp vec4 vShadeColor; \n" + "OUT highp vec4 vBaryCoords; \n" + ; + if (!_glinfo.isGLESX || _glinfo.noPerspective) + m_part += "noperspective OUT lowp vec4 vShadeColorNoperspective;\n"; + else + m_part += "OUT lowp vec4 vShadeColorNoperspective; \n"; + m_part += + "uniform lowp vec4 uRectColor; \n" + "void main() \n" + "{ \n" + " gl_Position = aRectPosition; \n" + " vShadeColor = uRectColor; \n" + " vShadeColorNoperspective = uRectColor; \n" + " vBaryCoords = vec4(aBaryCoords, vec2(1.0) - aBaryCoords);\n" + ; + } +}; + +class VertexShaderEnd : public ShaderPart +{ +public: + VertexShaderEnd(const opengl::GLInfo & _glinfo) + { + if (!_glinfo.isGLESX) { + m_part = + " gl_ClipDistance[0] = gl_Position.w - gl_Position.z; \n" + ; + } else if (config.generalEmulation.enableFragmentDepthWrite != 0 && _glinfo.noPerspective) { + m_part = + " vZCoord = gl_Position.z / gl_Position.w; \n" + " if (uClampMode > 0) \n" + " gl_Position.z = 0.0; \n" + ; + } else if (config.generalEmulation.enableClipping != 0) { + // Move the near plane towards the camera. + // It helps to avoid issues with near-plane clipping in games, which do not use it. + // Z must be scaled back in fragment shader. + m_part = " gl_Position.z /= 8.0; \n"; + } + m_part += + " gl_Position.xy += uVertexOffset * vec2(gl_Position.w); \n" + " gl_Position.xy -= vec2(0.5*screenSizeDims) * gl_Position.ww; \n" + " gl_Position.xy /= vec2(0.5*screenSizeDims); \n" + "} \n" + ; + } +}; + +class FragmentShaderHeader : public ShaderPart +{ +public: + FragmentShaderHeader(const opengl::GLInfo & _glinfo) + { + if (_glinfo.isGLES2) { + m_part = "#version 100 \n"; + if (config.generalEmulation.enableLOD) { + m_part += "#extension GL_EXT_shader_texture_lod : enable \n"; + m_part += "#extension GL_OES_standard_derivatives : enable \n"; + } + m_part += + "#if (__VERSION__ > 120) \n" + "# define IN in \n" + "# define OUT out \n" + "# define texture2D texture \n" + "#else \n" + "# define IN varying \n" + "# define OUT \n" + "#ifndef GL_FRAGMENT_PRECISION_HIGH \n" + "# define highp mediump \n" + "#endif \n" + "#endif // __VERSION __ \n" + ; + } else if (_glinfo.isGLESX) { + std::stringstream ss; + ss << "#version " << Utils::to_string(_glinfo.majorVersion) << Utils::to_string(_glinfo.minorVersion) << "0 es " << std::endl; + if (_glinfo.noPerspective) + ss << "#extension GL_NV_shader_noperspective_interpolation : enable" << std::endl; + if (_glinfo.dual_source_blending) + ss << "#extension GL_EXT_blend_func_extended : enable" << std::endl; + if (_glinfo.ext_fetch) + ss << "#extension GL_EXT_shader_framebuffer_fetch : enable" << std::endl; + if (_glinfo.ext_fetch_arm) + ss << "#extension GL_ARM_shader_framebuffer_fetch : enable" << std::endl; + + if (config.frameBufferEmulation.N64DepthCompare == Config::dcFast) { + if (_glinfo.imageTextures && _glinfo.fragment_interlockNV) { + ss << "#extension GL_NV_fragment_shader_interlock : enable" << std::endl + << "layout(pixel_interlock_ordered) in;" << std::endl; + } + } else if (_glinfo.fetch_depth) + ss << "#extension GL_ARM_shader_framebuffer_fetch_depth_stencil : enable" << std::endl; + + ss << "# define IN in" << std::endl + << "# define OUT out" << std::endl + << "# define texture2D texture" << std::endl; + m_part = ss.str(); + } else { + std::stringstream ss; + ss << "#version " << Utils::to_string(_glinfo.majorVersion) << Utils::to_string(_glinfo.minorVersion) << "0 core " << std::endl; + if (config.frameBufferEmulation.N64DepthCompare != Config::dcDisable) { + if (_glinfo.n64DepthWithFbFetch) + ss << "#extension GL_EXT_shader_framebuffer_fetch : enable" << std::endl; + else if (_glinfo.imageTextures) { + if (_glinfo.majorVersion * 10 + _glinfo.minorVersion < 42) { + ss << "#extension GL_ARB_shader_image_load_store : enable" << std::endl + << "#extension GL_ARB_shading_language_420pack : enable" << std::endl; + } + if (_glinfo.fragment_interlock) + ss << "#extension GL_ARB_fragment_shader_interlock : enable" << std::endl + << "layout(pixel_interlock_ordered) in;" << std::endl; + else if (_glinfo.fragment_interlockNV) + ss << "#extension GL_NV_fragment_shader_interlock : enable" << std::endl + << "layout(pixel_interlock_ordered) in;" << std::endl; + else if (_glinfo.fragment_ordering) + ss << "#extension GL_INTEL_fragment_shader_ordering : enable" << std::endl; + } + } + + ss << "# define IN in" << std::endl + << "# define OUT out" << std::endl + << "# define texture2D texture" << std::endl; + m_part = ss.str(); + } + m_part += + // Return the vector of the standard basis of R^4 with a 1 at position and 0 otherwise. + " #define STVEC(pos) (step(float(pos), vec4(0.5,1.5,2.5,3.5)) - step(float(pos), vec4(-0.5,0.5,1.5,2.5))) \n"; + + std::stringstream ss; + if (_glinfo.isGLES2) + ss << "const mediump float mipmapTileWidth = " << std::setprecision(1) << std::fixed << f32(MIPMAP_TILE_WIDTH) << ";" << std::endl; + else + ss << "const mediump int mipmapTileWidth = " << MIPMAP_TILE_WIDTH << ";" << std::endl; + m_part += ss.str(); + } +}; + +class ShaderBlender1 : public ShaderPart +{ +public: + ShaderBlender1(const opengl::GLInfo & _glinfo) + { +#if 1 + m_part = + " srcColor1 = vec4(0.0); \n" + " dstFactor1 = 0.0; \n" + " muxPM[0] = clampedColor; \n" + " muxA[0] = clampedColor.a; \n" + " muxa = MUXA(uBlendMux1[1]); \n" + " muxB[0] = 1.0 - muxa; \n" + " muxb = MUXB(uBlendMux1[3]); \n" + " muxp = MUXPM(uBlendMux1[0]); \n" + " muxm = MUXPM(uBlendMux1[2]); \n" + " muxaf = MUXF(uBlendMux1[0]); \n" + " muxbf = MUXF(uBlendMux1[2]); \n" + " if (uForceBlendCycle1 != 0) { \n" + " srcColor1 = muxp * muxa + muxm * muxb; \n" + " dstFactor1 = muxaf * muxa + muxbf * muxb; \n" + " srcColor1 = clamp(srcColor1, 0.0, 1.0); \n" + " } else { \n" + " srcColor1 = muxp; \n" + " dstFactor1 = muxaf; \n" + " } \n" + " fragColor = srcColor1; \n" + " fragColor1 = vec4(dstFactor1); \n" + ; +#else + // Keep old code for reference + m_part = + " muxPM[0] = clampedColor; \n" + " if (uForceBlendCycle1 != 0) { \n" + " muxA[0] = clampedColor.a; \n" + " muxB[0] = 1.0 - muxA[uBlendMux1[1]]; \n" + " lowp vec4 blend1 = (muxPM[uBlendMux1[0]] * muxA[uBlendMux1[1]]) + (muxPM[uBlendMux1[2]] * muxB[uBlendMux1[3]]); \n" + " clampedColor.rgb = clamp(blend1.rgb, 0.0, 1.0); \n" + " } else clampedColor.rgb = muxPM[uBlendMux1[0]].rgb; \n" + ; +#endif + } +}; + +class ShaderBlender2 : public ShaderPart +{ +public: + ShaderBlender2(const opengl::GLInfo & _glinfo) + { +#if 1 + m_part = + " srcColor2 = vec4(0.0); \n" + " dstFactor2 = 0.0; \n" + " muxPM[0] = srcColor1; \n" + " muxa = MUXA(uBlendMux2[1]); \n" + " muxB[0] = 1.0 - muxa; \n" + " muxb = MUXB(uBlendMux2[3]); \n" + " muxp = MUXPM(uBlendMux2[0]); \n" + " muxm = MUXPM(uBlendMux2[2]); \n" + " muxF[0] = dstFactor1; \n" + " muxaf = MUXF(uBlendMux2[0]); \n" + " muxbf = MUXF(uBlendMux2[2]); \n" + " if (uForceBlendCycle2 != 0) { \n" + " srcColor2 = muxp * muxa + muxm * muxb; \n" + " dstFactor2 = muxaf * muxa + muxbf * muxb; \n" + " srcColor2 = clamp(srcColor2, 0.0, 1.0); \n" + " } else { \n" + " srcColor2 = muxp; \n" + " dstFactor2 = muxaf; \n" + " } \n" + " fragColor = srcColor2; \n" + " fragColor1 = vec4(dstFactor2); \n" + ; + +#else + // Keep old code for reference + m_part = + " muxPM[0] = clampedColor; \n" + " muxPM[1] = vec4(0.0); \n" + " if (uForceBlendCycle2 != 0) { \n" + " muxA[0] = clampedColor.a; \n" + " muxB[0] = 1.0 - muxA[uBlendMux2[1]]; \n" + " lowp vec4 blend2 = muxPM[uBlendMux2[0]] * muxA[uBlendMux2[1]] + muxPM[uBlendMux2[2]] * muxB[uBlendMux2[3]]; \n" + " clampedColor.rgb = clamp(blend2.rgb, 0.0, 1.0); \n" + " } else clampedColor.rgb = muxPM[uBlendMux2[0]].rgb; \n" + ; +#endif + } +}; + +class ShaderBlenderAlpha : public ShaderPart +{ +public: + ShaderBlenderAlpha(const opengl::GLInfo & _glinfo) + { + if (_glinfo.dual_source_blending || _glinfo.ext_fetch || _glinfo.ext_fetch_arm) { + m_part += + "if (uBlendAlphaMode != 2) { \n" + " lowp vec4 srcAlpha = vec4(cvg, cvg, 1.0, 0.0); \n" + " lowp vec4 dstFactorAlpha = vec4(1.0, 1.0, 0.0, 1.0); \n" + " if (uBlendAlphaMode == 0) \n" + " dstFactorAlpha[0] = 0.0; \n" + " fragColor1.a = dstFactorAlpha[uCvgDest]; \n" + " fragColor.a = srcAlpha[uCvgDest] + lastFragColor.a * fragColor1.a;\n" + "} else fragColor.a = clampedColor.a; \n"; + } + else { + m_part += + "fragColor.a = clampedColor.a;" + ; + } + } +}; + +class ShaderLegacyBlender : public ShaderPart +{ +public: + ShaderLegacyBlender() + { + m_part = + " if (uFogUsage == 1) \n" + " fragColor.rgb = mix(fragColor.rgb, uFogColor.rgb, vShadeColor.a); \n" + ; + } +}; + + +/* +// N64 color wrap and clamp on floats +// See https://github.com/gonetz/GLideN64/issues/661 for reference +if (c < -1.0) return c + 2.0; + +if (c < -0.5) return 1; + +if (c < 0.0) return 0; + +if (c > 2.0) return c - 2.0; + +if (c > 1.5) return 0; + +if (c > 1.0) return 1; + +return c; +*/ +class ShaderClamp : public ShaderPart +{ +public: + ShaderClamp() + { + m_part = + " lowp vec4 wrappedColor = WRAP(cmbRes, -0.51, 1.51); \n" + " lowp vec4 clampedColor = clamp(wrappedColor, 0.0, 1.0); \n" + ; + } +}; + +/* +N64 sign-extension for C component of combiner +if (c > 1.0) +return c - 2.0; + +return c; +*/ +class ShaderSignExtendColorC : public ShaderPart +{ +public: + ShaderSignExtendColorC() + { + m_part = + " color1 = WRAP(color1, -1.01, 1.01); \n" + ; + } +}; + +class ShaderSignExtendAlphaC : public ShaderPart +{ +public: + ShaderSignExtendAlphaC() + { + m_part = + " alpha1 = WRAP(alpha1, -1.01, 1.01); \n" + ; + } +}; + +/* +N64 sign-extension for ABD components of combiner +if (c > 1.5) +return c - 2.0; + +if (c < -0.5) +return c + 2.0; + +return c; +*/ +class ShaderSignExtendColorABD : public ShaderPart +{ +public: + ShaderSignExtendColorABD() + { + m_part = + " color1 = WRAP(color1, -0.51, 1.51); \n" + ; + } +}; + +class ShaderSignExtendAlphaABD : public ShaderPart +{ +public: + ShaderSignExtendAlphaABD() + { + m_part = + " alpha1 = WRAP(alpha1, -0.51,1.51); \n" + ; + } +}; + +class ShaderAlphaTest : public ShaderPart +{ +public: + ShaderAlphaTest() + { + m_part = + " if (uEnableAlphaTest != 0) { \n" + " lowp float alphaTestValue = (uAlphaCompareMode == 3) ? snoise() : uAlphaTestValue; \n" + " lowp float alphaValue; \n" + " if ((uAlphaCvgSel != 0) && (uCvgXAlpha == 0)) { \n" + " alphaValue = 0.125; \n" + " } else { \n" + " alphaValue = clamp(alpha1, 0.0, 1.0); \n" + " } \n" + " if (alphaValue < alphaTestValue) discard; \n" + " } \n" + ; + } +}; + +class ShaderDithering : public ShaderPart +{ +public: + ShaderDithering(const opengl::GLInfo & _glinfo) + { + if (_glinfo.isGLES2) + return; + + if (config.generalEmulation.enableDitheringPattern == 0) { + m_part = + " if (uColorDitherMode == 2) { \n" + " colorDither(snoiseRGB(), clampedColor.rgb); \n" + " } \n" + " if (uAlphaDitherMode == 2) { \n" + " alphaDither(snoiseA(), clampedColor.a); \n" + " } \n" + ; + return; + } + + m_part += + " lowp mat4 bayer = mat4( 0.0, 0.5, 0.125, 0.625, \n" + " 0.5, 0.0, 0.625, 0.125, \n" + " 0.375, 0.875, 0.25, 0.75, \n" + " 0.875, 0.375, 0.75, 0.25); \n" + " lowp mat4 mSquare = mat4( 0.0, 0.75, 0.125, 0.875, \n" + " 0.5, 0.25, 0.625, 0.375, \n" + " 0.375, 0.625, 0.25, 0.5, \n" + " 0.875, 0.125, 0.75, 0.0); \n" + // Try to keep dithering visible even at higher resolutions + " lowp float divider = 1.0 + step(3.0, uScreenScale.x); \n" + " mediump ivec2 position = ivec2(mod((gl_FragCoord.xy - 0.5) / divider,4.0));\n" + " lowp vec4 posX = STVEC(position.x); \n" + " lowp vec4 posY = STVEC(position.y); \n" + " lowp float bayerThreshold = dot(bayer*posY, posX); \n" + " lowp float mSquareThreshold = dot(mSquare*posY, posX); \n" + " switch (uColorDitherMode) { \n" + " case 0: \n" + " colorDither(vec3(mSquareThreshold), clampedColor.rgb); \n" + " break; \n" + " case 1: \n" + " colorDither(vec3(bayerThreshold), clampedColor.rgb); \n" + " break; \n" + " case 2: \n" + " colorDither(snoiseRGB(), clampedColor.rgb); \n" + " break; \n" + " case 3: \n" + " break; \n" + " } \n" + " switch (uAlphaDitherMode) { \n" + " case 0: \n" + " switch (uColorDitherMode) { \n" + " case 0: \n" + " case 2: \n" + " alphaDither(mSquareThreshold, clampedColor.a); \n" + " break; \n" + " case 1: \n" + " case 3: \n" + " alphaDither(bayerThreshold, clampedColor.a); \n" + " break; \n" + " } \n" + " break; \n" + " case 1: \n" + " switch (uColorDitherMode) { \n" + " case 0: \n" + " case 2: \n" + " alphaDither(bayerThreshold, clampedColor.a); \n" + " break; \n" + " case 1: \n" + " case 3: \n" + " alphaDither(mSquareThreshold, clampedColor.a); \n" + " break; \n" + " } \n" + " break; \n" + " case 2: \n" + " alphaDither(snoiseA(), clampedColor.a); \n" + " break; \n" + " case 3: \n" + " break; \n" + " } \n" + ; + } +}; + +class ShaderFragmentGlobalVariablesNotex : public ShaderPart +{ +public: + ShaderFragmentGlobalVariablesNotex(const opengl::GLInfo & _glinfo) + { + m_part = + "uniform lowp vec4 uFogColor; \n" + "uniform lowp vec4 uCenterColor;\n" + "uniform lowp vec4 uScaleColor; \n" + "uniform lowp vec4 uBlendColor; \n" + "uniform lowp vec4 uEnvColor; \n" + "uniform lowp vec4 uPrimColor; \n" + "uniform lowp float uPrimLod; \n" + "uniform lowp float uK4; \n" + "uniform lowp float uK5; \n" + "uniform lowp int uAlphaCompareMode; \n" + "uniform lowp ivec2 uFbMonochrome; \n" + "uniform lowp ivec2 uFbFixedAlpha; \n" + "uniform lowp int uEnableAlphaTest; \n" + "uniform lowp int uCvgXAlpha; \n" + "uniform lowp int uAlphaCvgSel; \n" + "uniform lowp float uAlphaTestValue; \n" + "uniform lowp int uDepthSource; \n" + "uniform highp float uPrimDepth; \n" + "uniform mediump vec2 uScreenScale; \n" + "uniform lowp int uScreenSpaceTriangle; \n" + "uniform lowp int uCvgDest; \n" + "uniform lowp int uBlendAlphaMode; \n" + "lowp float cvg; \n" + ; + + if (config.generalEmulation.enableLegacyBlending != 0) { + m_part += + "uniform lowp int uFogUsage; \n" + ; + } else { + m_part += + "uniform lowp ivec4 uBlendMux1; \n" + "uniform lowp int uForceBlendCycle1;\n" + ; + } + + if (!_glinfo.isGLES2) { + m_part += + "uniform sampler2D uDepthTex; \n" + "uniform lowp int uAlphaDitherMode; \n" + "uniform lowp int uColorDitherMode; \n" + "uniform lowp int uRenderTarget; \n" + "uniform mediump vec2 uDepthScale; \n" + ; + if (config.frameBufferEmulation.N64DepthCompare != Config::dcDisable) { + m_part += + "uniform lowp int uEnableDepthCompare; \n" + ; + } + } else { + m_part += + "lowp int nCurrentTile; \n" + ; + } + + if (!_glinfo.isGLESX || _glinfo.noPerspective) + m_part += "noperspective IN lowp vec4 vShadeColorNoperspective; \n"; + else + m_part += "IN lowp vec4 vShadeColorNoperspective; \n"; + + m_part += + "IN lowp vec4 vShadeColor; \n" + "IN lowp float vNumLights; \n" + "IN highp vec4 vBaryCoords; \n" + ; + + if (_glinfo.dual_source_blending) { + m_part += + "layout(location = 0, index = 0) OUT lowp vec4 fragColor; \n" // MAIN FRAGMENT SHADER OUTPUT + "layout(location = 0, index = 1) OUT lowp vec4 fragColor1; \n" // SECONDARY FRAGMENT SHADER OUTPUT + "#define LAST_FRAG_COLOR vec4(0.0) \n" // DUMMY + "#define LAST_FRAG_ALPHA 1.0 \n" // DUMMY + ; + } else if (_glinfo.ext_fetch) { + m_part += + "layout(location = 0) inout lowp vec4 fragColor; \n" // MAIN FRAGMENT SHADER OUTPUT + "lowp vec4 fragColor1; \n" // DUMMY + "#define LAST_FRAG_COLOR fragColor \n" // CURRENT FRAMEBUFFER COLOR/ALPHA + "#define LAST_FRAG_ALPHA fragColor.a \n" // CURRENT FRAMEBUFFER ALPHA + ; + } else if (_glinfo.ext_fetch_arm) { + m_part += + "OUT lowp vec4 fragColor; \n" // MAIN FRAGMENT SHADER OUTPUT + "lowp vec4 fragColor1; \n" // DUMMY + "#define LAST_FRAG_COLOR gl_LastFragColorARM \n" // CURRENT FRAMEBUFFER COLOR/ALPHA + "#define LAST_FRAG_ALPHA gl_LastFragColorARM.a \n" // CURRENT FRAMEBUFFER ALPHA + ; + } else { + m_part += + "OUT lowp vec4 fragColor; \n" // MAIN FRAGMENT SHADER OUTPUT + "lowp vec4 fragColor1; \n" // DUMMY + "#define LAST_FRAG_COLOR vec4(0.0) \n" // DUMMY + "#define LAST_FRAG_ALPHA 1.0 \n" // DUMMY + ; + } + + if (config.frameBufferEmulation.N64DepthCompare == Config::dcFast && _glinfo.n64DepthWithFbFetch) { + m_part += + "layout(location = 1) inout highp vec4 depthZ; \n" + "layout(location = 2) inout highp vec4 depthDeltaZ; \n" + ; + } + } +}; + +class ShaderFragmentHeaderNoise : public ShaderPart +{ +public: + ShaderFragmentHeaderNoise(const opengl::GLInfo & _glinfo) + { + m_part = + "lowp float snoise();\n" + ; + } +}; + +class ShaderFragmentHeaderWriteDepth : public ShaderPart +{ +public: + ShaderFragmentHeaderWriteDepth(const opengl::GLInfo & _glinfo) + { + if (!_glinfo.isGLES2) { + m_part = + "highp float writeDepth();\n"; + ; + } + if (_glinfo.isGLESX && _glinfo.noPerspective) { + m_part = + "noperspective IN highp float vZCoord; \n" + "uniform lowp float uPolygonOffset; \n" + "uniform lowp int uClampMode; \n" + + m_part + ; + } + + } +}; + +class ShaderFragmentHeaderCalcLight : public ShaderPart +{ +public: + ShaderFragmentHeaderCalcLight(const opengl::GLInfo & _glinfo) + { + m_part = + "void calc_light(in lowp float fLights, in lowp vec3 input_color, out lowp vec3 output_color);\n"; + ; + } +}; + +class ShaderFragmentHeaderMipMap : public ShaderPart +{ +public: + ShaderFragmentHeaderMipMap(const opengl::GLInfo & _glinfo) + { + m_part = + "mediump float mipmap(out lowp vec4 readtex0, out lowp vec4 readtex1);\n"; + ; + } +}; + +class ShaderFragmentHeaderDither : public ShaderPart +{ +public: + ShaderFragmentHeaderDither(const opengl::GLInfo & _glinfo) + { + if (_glinfo.isGLES2) + return; + + m_part = + "void colorDither(in lowp vec3 _threshold, inout lowp vec3 _color);\n" + "void alphaDither(in lowp float _threshold, inout lowp float _alpha);\n" + "lowp vec3 snoiseRGB();\n" + "lowp float snoiseA();\n" + ; + } +}; + +class ShaderFragmentHeaderDepthCompare : public ShaderPart +{ +public: + ShaderFragmentHeaderDepthCompare(const opengl::GLInfo & _glinfo) + { + if (config.frameBufferEmulation.N64DepthCompare != Config::dcDisable) { + m_part = + "bool depth_compare(highp float curZ); \n" + "bool depth_render(highp float Z, highp float curZ); \n" + ; + if (_glinfo.imageTextures & !_glinfo.n64DepthWithFbFetch) { + m_part += + "layout(binding = 2, r32f) highp uniform restrict image2D uDepthImageZ; \n" + "layout(binding = 3, r32f) highp uniform restrict image2D uDepthImageDeltaZ; \n" + ; + } + } + } +}; + +class ShaderFragmentMain : public ShaderPart +{ +public: + ShaderFragmentMain(const opengl::GLInfo & _glinfo) + { + m_part = + "void main() \n" + "{ \n" + ; + if (!_glinfo.isGLES2) { + m_part += + " highp float fragDepth = writeDepth(); \n" + ; + } + m_part += + " lowp vec4 vec_color; \n" + " lowp float alpha1; \n" + " lowp vec3 color1, input_color; \n" + ; + if (config.generalEmulation.enableClipping != 0) + m_part += + " lowp vec4 shadeColor = vShadeColorNoperspective; \n" + ; + else + m_part += + " lowp vec4 shadeColor = uScreenSpaceTriangle == 0 ? vShadeColor : vShadeColorNoperspective; \n" + ; + + m_part += "#define WRAP(x, low, high) (mod((x)-(low), (high)-(low)) + (low)) \n"; // Return wrapped value of x in interval [low, high) + // m_part += "#define WRAP(x, low, high) (x) - ((high)-(low)) * floor(((x)-(low))/((high)-(low))) \n"; // Perhaps more compatible? + // m_part += "#define WRAP(x, low, high) (x) + ((high)-(low)) * (1.0-step(low,x)) - ((high)-(low)) * step(high,x) \n"; // Step based version. Only wraps correctly if input is in the range [low-(high-low), high + (high-low)). Similar to old code. + } + +}; + +class ShaderFragmentMain2Cycle : public ShaderPart +{ +public: + ShaderFragmentMain2Cycle(const opengl::GLInfo & _glinfo) + { + m_part = + "void main() \n" + "{ \n" + ; + if (!_glinfo.isGLES2) { + m_part += + " highp float fragDepth = writeDepth(); \n" + ; + } + m_part += + " lowp vec4 vec_color, combined_color; \n" + " lowp float alpha1, alpha2; \n" + " lowp vec3 color1, color2, input_color; \n" + ; + if (config.generalEmulation.enableClipping != 0) + m_part += + " lowp vec4 shadeColor = vShadeColorNoperspective; \n" + ; + else + m_part += + " lowp vec4 shadeColor = uScreenSpaceTriangle == 0 ? vShadeColor : vShadeColorNoperspective; \n" + ; + + m_part += "#define WRAP(x, low, high) mod((x)-(low), (high)-(low)) + (low) \n"; // Return wrapped value of x in interval [low, high) + // m_part += "#define WRAP(x, low, high) (x) - ((high)-(low)) * floor(((x)-(low))/((high)-(low))) \n"; // Perhaps more compatible? + // m_part += "#define WRAP(x, low, high) (x) + (2.0) * (1.0-step(low,x)) - (2.0) * step(high,x) \n"; // Step based version. Only wraps correctly if input is in the range [low-(high-low), high + (high-low)). Similar to old code. + } +}; + +class ShaderFragmentBlendMux : public ShaderPart +{ +public: + ShaderFragmentBlendMux(const opengl::GLInfo & _glinfo) + { + if (config.generalEmulation.enableLegacyBlending == 0) { + m_part = + " #define MUXA(pos) dot(muxA, STVEC(pos)) \n" + " #define MUXB(pos) dot(muxB, STVEC(pos)) \n" + " #define MUXPM(pos) muxPM*(STVEC(pos)) \n" + " #define MUXF(pos) dot(muxF, STVEC(pos)) \n" + " lowp vec4 lastFragColor = LAST_FRAG_COLOR; \n" + " lowp float lastFragAlpha = LAST_FRAG_ALPHA; \n" + " lowp mat4 muxPM = mat4(vec4(0.0), lastFragColor, uBlendColor, uFogColor); \n" + " lowp vec4 muxA = vec4(0.0, uFogColor.a, shadeColor.a, 0.0); \n" + " lowp vec4 muxB = vec4(0.0, lastFragAlpha, 1.0, 0.0); \n" + " lowp vec4 muxF = vec4(0.0, 1.0, 0.0, 0.0); \n" + " lowp vec4 muxp, muxm, srcColor1, srcColor2; \n" + " lowp float muxa, muxb, dstFactor1, dstFactor2, muxaf, muxbf; \n" + ; + } + } +}; + +class ShaderFragmentReadTexMipmap : public ShaderPart +{ +public: + ShaderFragmentReadTexMipmap(const opengl::GLInfo & _glinfo) + { + m_part = + " lowp vec4 readtex0, readtex1; \n" + " lowp float lod_frac = mipmap(readtex0, readtex1); \n" + ; + } +}; + +class ShaderFragmentCallN64Depth : public ShaderPart +{ +public: + ShaderFragmentCallN64Depth(const opengl::GLInfo & _glinfo) + { + if (config.frameBufferEmulation.N64DepthCompare != Config::dcDisable) { + m_part = " bool should_discard = false; \n"; + + if (_glinfo.imageTextures && !_glinfo.n64DepthWithFbFetch) { + if (_glinfo.fragment_interlock) + m_part += " beginInvocationInterlockARB(); \n"; + else if (_glinfo.fragment_interlockNV) + m_part += " beginInvocationInterlockNV(); \n"; + else if (_glinfo.fragment_ordering) + m_part += " beginFragmentShaderOrderingINTEL(); \n"; + } + + m_part += + " if (uRenderTarget != 0) { if (!depth_render(fragColor.r, fragDepth)) should_discard = true; } \n" + " else if (!depth_compare(fragDepth)) should_discard = true; \n" + ; + + if (_glinfo.imageTextures & !_glinfo.n64DepthWithFbFetch) { + if (_glinfo.fragment_interlock) + m_part += " endInvocationInterlockARB(); \n"; + else if (_glinfo.fragment_interlockNV) + m_part += " endInvocationInterlockNV(); \n"; + } + + m_part += " if (should_discard) discard; \n"; + + } + } +}; + +class ShaderFragmentRenderTarget : public ShaderPart +{ +public: + ShaderFragmentRenderTarget(const opengl::GLInfo & _glinfo) + { + if (config.generalEmulation.enableFragmentDepthWrite != 0) { + m_part = + " if (uRenderTarget != 0) { \n" + " if (uRenderTarget > 1) { \n" + " ivec2 coord = ivec2(gl_FragCoord.xy); \n" + " if (fragDepth >= texelFetch(uDepthTex, coord, 0).r) discard; \n" + " } \n" + " fragDepth = fragColor.r; \n" + " } \n" + " gl_FragDepth = fragDepth; \n" + ; + } + } +}; + +class ShaderFragmentMainEnd : public ShaderPart +{ +public: + ShaderFragmentMainEnd(const opengl::GLInfo & _glinfo) + { + if (_glinfo.isGLES2) { + m_part = + " gl_FragColor = fragColor; \n" + "} \n\n"; + } else { + m_part = + "} \n\n" + ; + } + } +}; + +class ShaderNoise : public ShaderPart +{ +public: + ShaderNoise(const opengl::GLInfo & _glinfo) + { + if (_glinfo.isGLES2) { + m_part = + "uniform sampler2D uTexNoise; \n" + "lowp float snoise() \n" + "{ \n" + " mediump vec2 texSize = vec2(640.0, 580.0); \n" + " mediump vec2 coord = gl_FragCoord.xy/uScreenScale/texSize; \n" + " return texture2D(uTexNoise, coord).r; \n" + "} \n" + ; + } else { + m_part = + "uniform sampler2D uTexNoise; \n" + "lowp float snoise() \n" + "{ \n" + " ivec2 coord = ivec2(gl_FragCoord.xy/uScreenScale); \n" + " return texelFetch(uTexNoise, coord, 0).r; \n" + "} \n" + ; + } + } +}; + +class ShaderDither : public ShaderPart +{ +public: + ShaderDither(const opengl::GLInfo & _glinfo) + { + if (_glinfo.isGLES2) + return; + + if (config.generalEmulation.enableDitheringQuantization != 0) { + m_part = + "void quantizeRGB(inout lowp vec3 _color) \n" + "{ \n" + " _color.rgb = round(_color.rgb * 32.0)/32.0; \n" + "} \n" + "void quantizeA(inout lowp float _alpha) \n" + "{ \n" + " _alpha = round(_alpha * 32.0)/32.0; \n" + "} \n" + ; + } else { + m_part = + "void quantizeRGB(inout lowp vec3 _color){}\n" + "void quantizeA(inout lowp float _alpha){}\n" + ; + } + + m_part += + "void colorDither(in lowp vec3 _noise, inout lowp vec3 _color)\n" + "{ \n" + " mediump vec3 threshold = 7.0 / 255.0 * (_noise - 0.5); \n" + " _color = clamp(_color + threshold,0.0,1.0); \n" + " quantizeRGB(_color); \n" + "} \n" + "void alphaDither(in lowp float _noise, inout lowp float _alpha)\n" + "{ \n" + " mediump float threshold = 7.0 / 255.0 * (_noise - 0.5); \n" + " _alpha = clamp(_alpha + threshold,0.0,1.0); \n" + " quantizeA(_alpha); \n" + "} \n" + "lowp vec3 snoiseRGB() \n" + "{ \n" + " mediump vec2 texSize = vec2(640.0, 580.0); \n" + ; + if (config.generalEmulation.enableHiresNoiseDithering != 0) + // multiplier for higher res noise effect + m_part += + " lowp float mult = 1.0 + step(2.0, uScreenScale.x); \n"; + else + m_part += + " lowp float mult = 1.0; \n"; + m_part += + " mediump vec2 coordR = mult * ((gl_FragCoord.xy)/uScreenScale/texSize);\n" + " mediump vec2 coordG = mult * ((gl_FragCoord.xy + vec2( 0.0, texSize.y / 2.0 ))/uScreenScale/texSize);\n" + " mediump vec2 coordB = mult * ((gl_FragCoord.xy + vec2( texSize.x / 2.0, 0.0))/uScreenScale/texSize);\n" + // Only red channel of noise texture contains noise. + " lowp float r = texture(uTexNoise,coordR).r; \n" + " lowp float g = texture(uTexNoise,coordG).r; \n" + " lowp float b = texture(uTexNoise,coordB).r; \n" + " \n" + " return vec3(r,g,b); \n" + "} \n" + "lowp float snoiseA() \n" + "{ \n" + " mediump vec2 texSize = vec2(640.0, 580.0); \n" + ; + if (config.generalEmulation.enableHiresNoiseDithering != 0) + // multiplier for higher res noise effect + m_part += + " lowp float mult = 1.0 + step(2.0, uScreenScale.x); \n"; + else + m_part += + " lowp float mult = 1.0; \n"; + m_part += + " \n" + " mediump vec2 coord = mult * ((gl_FragCoord.xy)/uScreenScale/texSize);\n" + " \n" + // Only red channel of noise texture contains noise. + " return texture(uTexNoise,coord).r; \n" + "} \n" + ; + } +}; + +class ShaderWriteDepth : public ShaderPart +{ +public: + ShaderWriteDepth(const opengl::GLInfo & _glinfo) + { + if (!_glinfo.isGLES2) { + if (config.generalEmulation.enableFragmentDepthWrite == 0 && + config.frameBufferEmulation.N64DepthCompare == Config::dcDisable) { + // Dummy write depth + m_part = + "highp float writeDepth() \n" + "{ \n" + " return 0.0; \n" + "} \n" + ; + } else { + if ((config.generalEmulation.hacks & hack_RE2) != 0) { + m_part = + "uniform lowp usampler2D uZlutImage;\n" + "highp float writeDepth() \n" + "{ \n" + ; + if (_glinfo.isGLESX) { + if (_glinfo.noPerspective) { + m_part += + " if (uClampMode == 1 && (vZCoord > 1.0)) discard; \n" + " highp float FragDepth = (uDepthSource != 0) ? uPrimDepth : \n" + " clamp((vZCoord - uPolygonOffset) * uDepthScale.s + uDepthScale.t, 0.0, 1.0); \n" + ; + } else if (config.generalEmulation.enableClipping != 0) { + m_part += + " highp float FragDepth = (uDepthSource != 0) ? uPrimDepth : \n" + " clamp(8.0 * (gl_FragCoord.z * 2.0 - 1.0) * uDepthScale.s + uDepthScale.t, 0.0, 1.0); \n" + ; + } else { + m_part += + " highp float FragDepth = (uDepthSource != 0) ? uPrimDepth : \n" + " clamp((gl_FragCoord.z * 2.0 - 1.0) * uDepthScale.s + uDepthScale.t, 0.0, 1.0); \n" + ; + } + } else { + m_part += + " highp float FragDepth = (uDepthSource != 0) ? uPrimDepth : \n" + " clamp((gl_FragCoord.z * 2.0 - 1.0) * uDepthScale.s + uDepthScale.t, 0.0, 1.0); \n" + ; + } + m_part += + " highp int iZ = FragDepth > 0.999 ? 262143 : int(floor(FragDepth * 262143.0)); \n" + " mediump int y0 = clamp(iZ/512, 0, 511); \n" + " mediump int x0 = iZ - 512*y0; \n" + " highp uint iN64z = texelFetch(uZlutImage,ivec2(x0,y0), 0).r; \n" + " return clamp(float(iN64z)/65532.0, 0.0, 1.0); \n" + "} \n" + ; + } else { + if (_glinfo.isGLESX) { + if (_glinfo.noPerspective) { + m_part = + "highp float writeDepth() \n" + "{ \n" + " if (uClampMode == 1 && (vZCoord > 1.0)) discard; \n" + " if (uDepthSource != 0) return uPrimDepth; \n" + " return clamp((vZCoord - uPolygonOffset) * uDepthScale.s + uDepthScale.t, 0.0, 1.0); \n" + "} \n" + ; + } else if (config.generalEmulation.enableClipping != 0) { + m_part = + "highp float writeDepth() \n" + "{ \n" + " if (uDepthSource != 0) return uPrimDepth; \n" + " return clamp(8.0 * (gl_FragCoord.z * 2.0 - 1.0) * uDepthScale.s + uDepthScale.t, 0.0, 1.0); \n" + "} \n" + ; + } else { + m_part = + "highp float writeDepth() \n" + "{ \n" + " if (uDepthSource != 0) return uPrimDepth; \n" + " return clamp((gl_FragCoord.z * 2.0 - 1.0) * uDepthScale.s + uDepthScale.t, 0.0, 1.0); \n" + "} \n" + ; + } + } else { + m_part = + "highp float writeDepth() \n" + "{ \n" + " if (uDepthSource != 0) return uPrimDepth; \n" + " return clamp((gl_FragCoord.z * 2.0 - 1.0) * uDepthScale.s + uDepthScale.t, 0.0, 1.0); \n" + "} \n" + ; + } + } + } + } + } +}; + +class ShaderCalcLight : public ShaderPart +{ +public: + ShaderCalcLight(const opengl::GLInfo & /*_glinfo*/) + { + m_part = + "uniform mediump vec3 uLightDirection[8]; \n" + "uniform lowp vec3 uLightColor[8]; \n" + "void calc_light(in lowp float fLights, in lowp vec3 input_color, out lowp vec3 output_color) {\n" + " output_color = input_color; \n" + " lowp int nLights = int(floor(fLights + 0.5)); \n" + " if (nLights == 0) \n" + " return; \n" + " output_color = uLightColor[nLights]; \n" + " mediump float intensity; \n" + " for (int i = 0; i < nLights; i++) { \n" + " intensity = max(dot(input_color, uLightDirection[i]), 0.0);\n" + " output_color += intensity*uLightColor[i]; \n" + " }; \n" + " output_color = clamp(output_color, 0.0, 1.0); \n" + "} \n" + ; + } +}; + +class ShaderN64DepthCompare : public ShaderPart +{ +public: + ShaderN64DepthCompare(const opengl::GLInfo & _glinfo) + { + if (config.frameBufferEmulation.N64DepthCompare != Config::dcDisable) { + m_part = + "uniform lowp int uEnableDepth; \n" + "uniform lowp int uDepthMode; \n" + "uniform lowp int uEnableDepthUpdate; \n" + "uniform mediump float uDeltaZ; \n" + "bool depth_compare(highp float curZ) \n" + "{ \n" + " if (uEnableDepth == 0) return true; \n" + ; + if (_glinfo.imageTextures && !_glinfo.n64DepthWithFbFetch) { + m_part += + " ivec2 coord = ivec2(gl_FragCoord.xy); \n" + " highp vec4 depthZ = imageLoad(uDepthImageZ,coord); \n" + " highp vec4 depthDeltaZ = imageLoad(uDepthImageDeltaZ,coord);\n" + ; + } + m_part += + " highp float bufZ = depthZ.r; \n" + " highp float dz, dzMin; \n" + " if (uDepthSource == 1) { \n" + " dzMin = dz = uDeltaZ; \n" + " } else { \n" + " dz = 4.0*fwidth(curZ); \n" + " dzMin = min(dz, depthDeltaZ.r); \n" + " } \n" + " bool bInfront = curZ < bufZ; \n" + " bool bFarther = (curZ + dzMin) >= bufZ; \n" + " bool bNearer = (curZ - dzMin) <= bufZ; \n" + " bool bMax = bufZ == 1.0; \n" + " bool bRes = false; \n" + " switch (uDepthMode) { \n" + " case 1: \n" + " bRes = bMax || bNearer; \n" + " break; \n" + " case 0: \n" + " case 2: \n" + " bRes = bMax || bInfront; \n" + " break; \n" + " case 3: \n" + " bRes = bFarther && bNearer && !bMax; \n" + " break; \n" + " } \n" + " bRes = bRes || (uEnableDepthCompare == 0); \n" + " if (uEnableDepthUpdate != 0 && bRes) { \n" + ; + if (_glinfo.n64DepthWithFbFetch) { + m_part += + " depthZ.r = curZ; \n" + " depthDeltaZ.r = dz; \n" + ; + } else if (_glinfo.imageTextures) { + m_part += + " highp vec4 depthOutZ = vec4(curZ, 1.0, 1.0, 1.0); \n" + " highp vec4 depthOutDeltaZ = vec4(dz, 1.0, 1.0, 1.0); \n" + " imageStore(uDepthImageZ, coord, depthOutZ); \n" + " imageStore(uDepthImageDeltaZ, coord, depthOutDeltaZ); \n" + ; + } + + m_part += + " } \n" + " return bRes; \n" + "} \n" + ; + } + } +}; + +class ShaderN64DepthRender : public ShaderPart +{ +public: + ShaderN64DepthRender(const opengl::GLInfo & _glinfo) + { + if (config.frameBufferEmulation.N64DepthCompare != Config::dcDisable) { + m_part = + "bool depth_render(highp float Z, highp float curZ) \n" + "{ \n" + " ivec2 coord = ivec2(gl_FragCoord.xy); \n" + " if (uEnableDepthCompare != 0) { \n" + ; + if (_glinfo.imageTextures && !_glinfo.n64DepthWithFbFetch) { + m_part += + " highp vec4 depthZ = imageLoad(uDepthImageZ,coord); \n" + ; + } + m_part += + " highp float bufZ = depthZ.r; \n" + " if (curZ >= bufZ) return false; \n" + " } \n" + ; + if (_glinfo.n64DepthWithFbFetch) { + m_part += + " depthZ.r = Z; \n" + " depthDeltaZ.r = 0.0; \n" + ; + } else if (_glinfo.imageTextures) { + m_part += + " highp vec4 depthOutZ = vec4(Z, 1.0, 1.0, 1.0); \n" + " highp vec4 depthOutDeltaZ = vec4(0.0, 1.0, 1.0, 1.0);\n" + " imageStore(uDepthImageZ,coord, depthOutZ); \n" + " imageStore(uDepthImageDeltaZ,coord, depthOutDeltaZ); \n" + ; + } + + m_part += + " return true; \n" + "} \n" + ; + } + } +}; + +class ShaderFragmentCorrectTexCoords : public ShaderPart { +public: + ShaderFragmentCorrectTexCoords() { + m_part += + " highp vec2 mTexCoord0 = vTexCoord0 + vec2(0.0001); \n" + " highp vec2 mTexCoord1 = vTexCoord1 + vec2(0.0001); \n" + " mTexCoord0 += uTexCoordOffset[0]; \n" + " mTexCoord1 += uTexCoordOffset[1]; \n" + " if (uUseTexCoordBounds != 0) { \n" + " mTexCoord0 = clamp(mTexCoord0, uTexCoordBounds0.xy, uTexCoordBounds0.zw); \n" + " mTexCoord1 = clamp(mTexCoord1, uTexCoordBounds1.xy, uTexCoordBounds1.zw); \n" + " } \n" + ; + } +}; + +class ShaderCoverage : public ShaderPart { +public: + ShaderCoverage() { + m_part = + "const highp vec2 bias[8] = vec2[8] (vec2(-0.5,-0.5), vec2(0.0, -0.5), vec2(-0.25,-0.25), vec2(0.25, -0.25), \n" + " vec2(-0.5, 0.0), vec2(0.0,0.0), vec2(-0.25,0.25), vec2(0.25,0.25)); \n" + "highp vec4 dBCdx = dFdx(vBaryCoords); \n" + "highp vec4 dBCdy = dFdy(vBaryCoords); \n" + "cvg = 0.0; \n" + "for (int i = 0; i<8; i++) { \n" + " highp vec2 currentBias = bias[i]; \n" + " highp vec4 baryCoordsBiased = vBaryCoords + dBCdx*currentBias.x + dBCdy * currentBias.y; \n" + " lowp vec4 inside = step(0.0, baryCoordsBiased); \n" + " cvg += 0.125 * inside[0] * inside[1] * inside[2] * inside[3]; \n" + "} \n" + ; + } +}; + +/*---------------ShaderPartsEnd-------------*/ + +static +GLuint _createVertexShader(ShaderPart * _header, ShaderPart * _body, ShaderPart * _footer) +{ + std::stringstream ssShader; + _header->write(ssShader); + _body->write(ssShader); + _footer->write(ssShader); + const std::string strShader(ssShader.str()); + const GLchar * strShaderData = strShader.data(); + + GLuint shader_object = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(shader_object, 1, &strShaderData, nullptr); + glCompileShader(shader_object); + if (!Utils::checkShaderCompileStatus(shader_object)) + Utils::logErrorShader(GL_VERTEX_SHADER, strShaderData); + return shader_object; +} + +CombinerProgramBuilderCommon::CombinerProgramBuilderCommon(const opengl::GLInfo & _glinfo, opengl::CachedUseProgram * _useProgram, + std::unique_ptr _uniformFactory, + std::unique_ptr _vertexTexturedTriangle) +: CombinerProgramBuilder(_glinfo, _useProgram, std::move(_uniformFactory)) +, m_blender1(new ShaderBlender1(_glinfo)) +, m_blender2(new ShaderBlender2(_glinfo)) +, m_blenderAlpha (new ShaderBlenderAlpha(_glinfo)) +, m_legacyBlender(new ShaderLegacyBlender) +, m_clamp(new ShaderClamp) +, m_signExtendColorC(new ShaderSignExtendColorC) +, m_signExtendAlphaC(new ShaderSignExtendAlphaC) +, m_signExtendColorABD(new ShaderSignExtendColorABD) +, m_signExtendAlphaABD(new ShaderSignExtendAlphaABD) +, m_alphaTest(new ShaderAlphaTest) +, m_callDither(new ShaderDithering(_glinfo)) +, m_vertexHeader(new VertexShaderHeader(_glinfo)) +, m_vertexEnd(new VertexShaderEnd(_glinfo)) +, m_vertexRect(new VertexShaderRect(_glinfo)) +, m_vertexTexturedRect(new VertexShaderTexturedRect(_glinfo)) +, m_vertexTriangle(new VertexShaderTriangle(_glinfo)) +, m_fragmentHeader(new FragmentShaderHeader(_glinfo)) +, m_fragmentGlobalVariablesNotex(new ShaderFragmentGlobalVariablesNotex(_glinfo)) +, m_fragmentHeaderNoise(new ShaderFragmentHeaderNoise(_glinfo)) +, m_fragmentHeaderWriteDepth(new ShaderFragmentHeaderWriteDepth(_glinfo)) +, m_fragmentHeaderCalcLight(new ShaderFragmentHeaderCalcLight(_glinfo)) +, m_fragmentHeaderMipMap(new ShaderFragmentHeaderMipMap(_glinfo)) +, m_fragmentHeaderDither(new ShaderFragmentHeaderDither(_glinfo)) +, m_fragmentHeaderDepthCompare(new ShaderFragmentHeaderDepthCompare(_glinfo)) +, m_fragmentMain(new ShaderFragmentMain(_glinfo)) +, m_fragmentMain2Cycle(new ShaderFragmentMain2Cycle(_glinfo)) +, m_fragmentBlendMux(new ShaderFragmentBlendMux(_glinfo)) +, m_fragmentCorrectTexCoords(new ShaderFragmentCorrectTexCoords()) +, m_fragmentReadTexMipmap(new ShaderFragmentReadTexMipmap(_glinfo)) +, m_fragmentCallN64Depth(new ShaderFragmentCallN64Depth(_glinfo)) +, m_fragmentRenderTarget(new ShaderFragmentRenderTarget(_glinfo)) +, m_shaderFragmentMainEnd(new ShaderFragmentMainEnd(_glinfo)) +, m_shaderNoise(new ShaderNoise(_glinfo)) +, m_shaderDither(new ShaderDither(_glinfo)) +, m_shaderWriteDepth(new ShaderWriteDepth(_glinfo)) +, m_shaderCalcLight(new ShaderCalcLight(_glinfo)) +, m_shaderN64DepthCompare(new ShaderN64DepthCompare(_glinfo)) +, m_shaderN64DepthRender(new ShaderN64DepthRender(_glinfo)) +, m_shaderCoverage(new ShaderCoverage()) +, m_combinerOptionsBits(graphics::CombinerProgram::getShaderCombinerOptionsBits()) +{ + m_vertexShaderRect = _createVertexShader(m_vertexHeader.get(), m_vertexRect.get(), m_vertexEnd.get()); + m_vertexShaderTriangle = _createVertexShader(m_vertexHeader.get(), m_vertexTriangle.get(), m_vertexEnd.get()); + m_vertexShaderTexturedRect = _createVertexShader(m_vertexHeader.get(), m_vertexTexturedRect.get(), m_vertexEnd.get()); + m_vertexShaderTexturedTriangle = _createVertexShader(m_vertexHeader.get(), _vertexTexturedTriangle.get(), m_vertexEnd.get()); +} + +CombinerProgramBuilderCommon::~CombinerProgramBuilderCommon() +{ + glDeleteShader(m_vertexShaderRect); + glDeleteShader(m_vertexShaderTriangle); + glDeleteShader(m_vertexShaderTexturedRect); + glDeleteShader(m_vertexShaderTexturedTriangle); +} + +const ShaderPart * CombinerProgramBuilderCommon::getVertexShaderHeader() const +{ + return m_vertexHeader.get(); +} + +const ShaderPart * CombinerProgramBuilderCommon::getFragmentShaderHeader() const +{ + return m_fragmentHeader.get(); +} + +const ShaderPart * CombinerProgramBuilderCommon::getFragmentShaderEnd() const +{ + return m_shaderFragmentMainEnd.get(); +} + +bool CombinerProgramBuilderCommon::isObsolete() const +{ + return m_combinerOptionsBits != graphics::CombinerProgram::getShaderCombinerOptionsBits(); +} + +GLuint CombinerProgramBuilderCommon::_getVertexShaderRect() const +{ + return m_vertexShaderRect; +} + +GLuint CombinerProgramBuilderCommon::_getVertexShaderTriangle() const +{ + return m_vertexShaderTriangle; +} + +GLuint CombinerProgramBuilderCommon::_getVertexShaderTexturedRect() const +{ + return m_vertexShaderTexturedRect; +} + +GLuint CombinerProgramBuilderCommon::_getVertexShaderTexturedTriangle() const +{ + return m_vertexShaderTexturedTriangle; +} + +void CombinerProgramBuilderCommon::_writeSignExtendAlphaC(std::stringstream& ssShader)const +{ + m_signExtendAlphaC->write(ssShader); +} + +void CombinerProgramBuilderCommon::_writeSignExtendAlphaABD(std::stringstream& ssShader)const +{ + m_signExtendAlphaABD->write(ssShader); +} + +void CombinerProgramBuilderCommon::_writeAlphaTest(std::stringstream& ssShader)const +{ + m_alphaTest->write(ssShader); +} + +void CombinerProgramBuilderCommon::_writeSignExtendColorC(std::stringstream& ssShader)const +{ + m_signExtendColorC->write(ssShader); +} + +void CombinerProgramBuilderCommon::_writeSignExtendColorABD(std::stringstream& ssShader)const +{ + m_signExtendColorABD->write(ssShader); +} + +void CombinerProgramBuilderCommon::_writeClamp(std::stringstream& ssShader)const +{ + m_clamp->write(ssShader); +} + +void CombinerProgramBuilderCommon::_writeCallDither(std::stringstream& ssShader)const +{ + m_callDither->write(ssShader); +} + +void CombinerProgramBuilderCommon::_writeBlender1(std::stringstream& ssShader)const +{ + m_blender1->write(ssShader); +} + +void CombinerProgramBuilderCommon::_writeBlender2(std::stringstream& ssShader)const +{ + m_blender2->write(ssShader); +} + +void CombinerProgramBuilderCommon::_writeBlenderAlpha(std::stringstream& ssShader)const +{ + m_blenderAlpha->write(ssShader); +} + +void CombinerProgramBuilderCommon::_writeLegacyBlender(std::stringstream& ssShader)const +{ + m_legacyBlender->write(ssShader); +} + +void CombinerProgramBuilderCommon::_writeFragmentHeader(std::stringstream& ssShader)const +{ + m_fragmentHeader->write(ssShader); +} + +void CombinerProgramBuilderCommon::_writeFragmentHeaderDither(std::stringstream& ssShader)const +{ + m_fragmentHeaderDither->write(ssShader); +} + +void CombinerProgramBuilderCommon::_writeFragmentHeaderNoise(std::stringstream& ssShader)const +{ + m_fragmentHeaderNoise->write(ssShader); +} + +void CombinerProgramBuilderCommon::_writeFragmentHeaderWriteDepth(std::stringstream& ssShader)const +{ + m_fragmentHeaderWriteDepth->write(ssShader); +} + +void CombinerProgramBuilderCommon::_writeFragmentHeaderDepthCompare(std::stringstream& ssShader)const +{ + m_fragmentHeaderDepthCompare->write(ssShader); +} + +void CombinerProgramBuilderCommon::_writeFragmentHeaderMipMap(std::stringstream& ssShader)const +{ + m_fragmentHeaderMipMap->write(ssShader); +} + +void CombinerProgramBuilderCommon::_writeFragmentGlobalVariablesNotex(std::stringstream& ssShader)const +{ + m_fragmentGlobalVariablesNotex->write(ssShader); +} + +void CombinerProgramBuilderCommon::_writeFragmentHeaderCalcLight(std::stringstream& ssShader)const +{ + m_fragmentHeaderCalcLight->write(ssShader); +} + +void CombinerProgramBuilderCommon::_writeFragmentMain2Cycle(std::stringstream& ssShader)const +{ + m_fragmentMain2Cycle->write(ssShader); +} + +void CombinerProgramBuilderCommon::_writeFragmentMain(std::stringstream& ssShader)const +{ + m_fragmentMain->write(ssShader); +} + +void CombinerProgramBuilderCommon::_writeFragmentBlendMux(std::stringstream& ssShader)const +{ + m_fragmentBlendMux->write(ssShader); +} + +void CombinerProgramBuilderCommon::_writeShaderCoverage(std::stringstream& ssShader)const +{ + m_shaderCoverage->write(ssShader); +} + +void CombinerProgramBuilderCommon::_writeFragmentCorrectTexCoords(std::stringstream& ssShader)const +{ + m_fragmentCorrectTexCoords->write(ssShader); +} + +void CombinerProgramBuilderCommon::_writeFragmentReadTexMipmap(std::stringstream& ssShader)const +{ + m_fragmentReadTexMipmap->write(ssShader); +} + +void CombinerProgramBuilderCommon::_writeFragmentCallN64Depth(std::stringstream& ssShader)const +{ + m_fragmentCallN64Depth->write(ssShader); +} + +void CombinerProgramBuilderCommon::_writeFragmentRenderTarget(std::stringstream& ssShader)const +{ + m_fragmentRenderTarget->write(ssShader); +} + +void CombinerProgramBuilderCommon::_writeShaderFragmentMainEnd(std::stringstream& ssShader)const +{ + m_shaderFragmentMainEnd->write(ssShader); +} + +void CombinerProgramBuilderCommon::_writeShaderCalcLight(std::stringstream& ssShader)const +{ + m_shaderCalcLight->write(ssShader); +} + +void CombinerProgramBuilderCommon::_writeShaderNoise(std::stringstream& ssShader)const +{ + m_shaderNoise->write(ssShader); +} + +void CombinerProgramBuilderCommon::_writeShaderDither(std::stringstream& ssShader)const +{ + m_shaderDither->write(ssShader); +} + +void CombinerProgramBuilderCommon::_writeShaderWriteDepth(std::stringstream& ssShader)const +{ + m_shaderWriteDepth->write(ssShader); +} + +void CombinerProgramBuilderCommon::_writeShaderN64DepthCompare(std::stringstream& ssShader)const +{ + m_shaderN64DepthCompare->write(ssShader); +} + +void CombinerProgramBuilderCommon::_writeShaderN64DepthRender(std::stringstream& ssShader)const +{ + m_shaderN64DepthRender->write(ssShader); +} + +} \ No newline at end of file diff --git a/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilderCommon.h b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilderCommon.h new file mode 100644 index 00000000..d7fa6177 --- /dev/null +++ b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilderCommon.h @@ -0,0 +1,118 @@ +#pragma once +#include + +namespace glsl { + +class CombinerProgramUniformFactory; + +class CombinerProgramBuilderCommon : public glsl::CombinerProgramBuilder +{ +public: + CombinerProgramBuilderCommon(const opengl::GLInfo & _glinfo, opengl::CachedUseProgram * _useProgram, + std::unique_ptr _uniformFactory, + std::unique_ptr _vertexTexturedTriangle); + ~CombinerProgramBuilderCommon(); + + const ShaderPart * getVertexShaderHeader() const override; + + const ShaderPart * getFragmentShaderHeader() const override; + + const ShaderPart * getFragmentShaderEnd() const override; + + bool isObsolete() const override; + +private: + + GLuint _getVertexShaderRect() const override; + GLuint _getVertexShaderTriangle() const override; + GLuint _getVertexShaderTexturedRect() const override; + GLuint _getVertexShaderTexturedTriangle() const override; + + void _writeSignExtendAlphaC(std::stringstream& ssShader) const override; + void _writeSignExtendAlphaABD(std::stringstream& ssShader) const override; + void _writeAlphaTest(std::stringstream& ssShader) const override; + void _writeSignExtendColorC(std::stringstream& ssShader) const override; + void _writeSignExtendColorABD(std::stringstream& ssShader) const override; + void _writeClamp(std::stringstream& ssShader) const override; + void _writeCallDither(std::stringstream& ssShader) const override; + void _writeBlender1(std::stringstream& ssShader) const override; + void _writeBlender2(std::stringstream& ssShader) const override; + void _writeBlenderAlpha(std::stringstream& ssShader) const override; + void _writeLegacyBlender(std::stringstream& ssShader) const override; + void _writeFragmentHeader(std::stringstream& ssShader) const override; + void _writeFragmentHeaderDither(std::stringstream& ssShader) const override; + void _writeFragmentHeaderNoise(std::stringstream& ssShader) const override; + void _writeFragmentHeaderWriteDepth(std::stringstream& ssShader) const override; + void _writeFragmentHeaderDepthCompare(std::stringstream& ssShader) const override; + void _writeFragmentHeaderMipMap(std::stringstream& ssShader) const override; + void _writeFragmentGlobalVariablesNotex(std::stringstream& ssShader) const override; + void _writeFragmentHeaderCalcLight(std::stringstream& ssShader) const override; + void _writeFragmentMain2Cycle(std::stringstream& ssShader) const override; + void _writeFragmentMain(std::stringstream& ssShader) const override; + void _writeFragmentBlendMux(std::stringstream& ssShader) const override; + void _writeShaderCoverage(std::stringstream& ssShader) const override; + void _writeFragmentCorrectTexCoords(std::stringstream& ssShader) const override; + void _writeFragmentReadTexMipmap(std::stringstream& ssShader) const override; + void _writeFragmentCallN64Depth(std::stringstream& ssShader) const override; + void _writeFragmentRenderTarget(std::stringstream& ssShader) const override; + void _writeShaderFragmentMainEnd(std::stringstream& ssShader) const override; + void _writeShaderCalcLight(std::stringstream& ssShader) const override; + void _writeShaderNoise(std::stringstream& ssShader) const override; + void _writeShaderDither(std::stringstream& ssShader) const override; + void _writeShaderWriteDepth(std::stringstream& ssShader) const override; + void _writeShaderN64DepthCompare(std::stringstream& ssShader) const override; + void _writeShaderN64DepthRender(std::stringstream& ssShader) const override; + + ShaderPartPtr m_blender1; + ShaderPartPtr m_blender2; + ShaderPartPtr m_blenderAlpha; + ShaderPartPtr m_legacyBlender; + ShaderPartPtr m_clamp; + ShaderPartPtr m_signExtendColorC; + ShaderPartPtr m_signExtendAlphaC; + ShaderPartPtr m_signExtendColorABD; + ShaderPartPtr m_signExtendAlphaABD; + ShaderPartPtr m_alphaTest; + ShaderPartPtr m_callDither; + + ShaderPartPtr m_vertexHeader; + ShaderPartPtr m_vertexEnd; + ShaderPartPtr m_vertexRect; + ShaderPartPtr m_vertexTexturedRect; + ShaderPartPtr m_vertexTriangle; + + ShaderPartPtr m_fragmentHeader; + ShaderPartPtr m_fragmentGlobalVariablesNotex; + ShaderPartPtr m_fragmentHeaderNoise; + ShaderPartPtr m_fragmentHeaderWriteDepth; + ShaderPartPtr m_fragmentHeaderCalcLight; + ShaderPartPtr m_fragmentHeaderMipMap; + ShaderPartPtr m_fragmentHeaderDither; + ShaderPartPtr m_fragmentHeaderDepthCompare; + ShaderPartPtr m_fragmentMain; + ShaderPartPtr m_fragmentMain2Cycle; + ShaderPartPtr m_fragmentBlendMux; + ShaderPartPtr m_fragmentCorrectTexCoords; + ShaderPartPtr m_fragmentReadTexMipmap; + ShaderPartPtr m_fragmentCallN64Depth; + ShaderPartPtr m_fragmentRenderTarget; + ShaderPartPtr m_shaderFragmentMainEnd; + + ShaderPartPtr m_shaderNoise; + ShaderPartPtr m_shaderDither; + ShaderPartPtr m_shaderWriteDepth; + ShaderPartPtr m_shaderCalcLight; + ShaderPartPtr m_shaderN64DepthCompare; + ShaderPartPtr m_shaderN64DepthRender; + ShaderPartPtr m_shaderCoverage; + + u32 m_combinerOptionsBits; + + GLuint m_vertexShaderRect; + GLuint m_vertexShaderTriangle; + GLuint m_vertexShaderTexturedRect; + GLuint m_vertexShaderTexturedTriangle; +}; + +} + diff --git a/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilderFast.cpp b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilderFast.cpp new file mode 100644 index 00000000..2dfcdbb9 --- /dev/null +++ b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilderFast.cpp @@ -0,0 +1,1186 @@ +#include // for setprecision +#include +#include +#include +#include "glsl_Utils.h" +#include "glsl_CombinerInputs.h" +#include "glsl_CombinerProgramImpl.h" +#include "glsl_CombinerProgramBuilderFast.h" +#include "glsl_CombinerProgramUniformFactoryFast.h" +#include "GraphicsDrawer.h" + +namespace glsl { + +class VertexShaderTexturedTriangleFast : public ShaderPart +{ +public: + VertexShaderTexturedTriangleFast(const opengl::GLInfo & _glinfo) + { + m_part = + "IN highp vec4 aPosition; \n" + "IN lowp vec4 aColor; \n" + "IN highp vec2 aTexCoord; \n" + "IN lowp float aNumLights; \n" + "IN highp vec4 aModify; \n" + "IN highp vec2 aBaryCoords; \n" + " \n" + "uniform int uTexturePersp; \n" + "uniform lowp int uTextureFilterMode; \n" + " \n" + "uniform lowp int uFogUsage; \n" + "uniform mediump vec2 uFogScale; \n" + "uniform mediump vec2 uScreenCoordsScale; \n" + " \n" + "uniform mediump vec2 uTexScale; \n" + "uniform mediump vec2 uTexOffset[2]; \n" + "uniform mediump vec2 uCacheScale[2]; \n" + "uniform mediump vec2 uCacheOffset[2]; \n" + "uniform mediump vec2 uCacheShiftScale[2]; \n" + "uniform mediump vec2 uVTrans; \n" + "uniform mediump vec2 uVScale; \n" + "uniform mediump vec2 uAdjustTrans; \n" + "uniform mediump vec2 uAdjustScale; \n" + "uniform lowp ivec2 uCacheFrameBuffer; \n" + "OUT highp vec2 vTexCoord0; \n" + "OUT highp vec2 vTexCoord1; \n" + "OUT mediump vec2 vLodTexCoord; \n" + "OUT lowp float vNumLights; \n" + "OUT lowp vec4 vShadeColor; \n" + "OUT highp vec4 vBaryCoords; \n" + ; + if (!_glinfo.isGLESX || _glinfo.noPerspective) + m_part += "noperspective OUT lowp vec4 vShadeColorNoperspective;\n"; + else + m_part += "OUT lowp vec4 vShadeColorNoperspective; \n"; + m_part += + "mediump vec2 calcTexCoord(in vec2 texCoord, in int idx) \n" + "{ \n" + " vec2 texCoordOut = texCoord*uCacheShiftScale[idx]; \n" + " texCoordOut -= uTexOffset[idx]; \n" + " texCoordOut += uCacheOffset[idx]; \n" + " if (uTextureFilterMode != 0 && uCacheFrameBuffer[idx] != 0) \n" /* Workaround for framebuffer textures. */ + " texCoordOut -= vec2(0.0,1.0); \n" /* They contain garbage at the bottom. */ + " return texCoordOut * uCacheScale[idx]; \n" + "} \n" + " \n" + "void main() \n" + "{ \n" + " gl_Position = aPosition; \n" + " vShadeColor = aColor; \n" + " vec2 texCoord = aTexCoord; \n" + " texCoord *= uTexScale; \n" + " if (uTexturePersp == 0 && aModify[2] == 0.0) texCoord *= 0.5;\n" + " vTexCoord0 = calcTexCoord(texCoord, 0); \n" + " vTexCoord1 = calcTexCoord(texCoord, 1); \n" + " vLodTexCoord = texCoord; \n" + " vNumLights = aNumLights; \n" + " if ((aModify[0]) != 0.0) { \n" + " gl_Position.xy *= gl_Position.w; \n" + " } \n" + " else { \n" + " gl_Position.xy = gl_Position.xy * uVScale.xy + uVTrans.xy * gl_Position.ww; \n" + " gl_Position.xy = floor(gl_Position.xy * vec2(4.0)) * vec2(0.25); \n" + " gl_Position.xy = gl_Position.xy * uAdjustScale + gl_Position.ww * uAdjustTrans; \n" + " } \n" + " if ((aModify[1]) != 0.0) \n" + " gl_Position.z *= gl_Position.w; \n" + " if ((aModify[3]) != 0.0) \n" + " vNumLights = 0.0; \n" + " if (uFogUsage > 0) { \n" + " lowp float fp; \n" + " if (aPosition.z < -aPosition.w && aModify[1] == 0.0) \n" + " fp = -uFogScale.s + uFogScale.t; \n" + " else \n" + " fp = aPosition.z/aPosition.w*uFogScale.s + uFogScale.t; \n" + " fp = clamp(fp, 0.0, 1.0); \n" + " if (uFogUsage == 1) \n" + " vShadeColor.a = fp; \n" + " else \n" + " vShadeColor.rgb = vec3(fp); \n" + " } \n" + " vBaryCoords = vec4(aBaryCoords, 1.0 - aBaryCoords.x - aBaryCoords.y, 0.5); \n" + " vShadeColorNoperspective = vShadeColor; \n" + ; + } +}; + +class ShaderFragmentGlobalVariablesTexFast : public ShaderPart +{ +public: + ShaderFragmentGlobalVariablesTexFast(const opengl::GLInfo & _glinfo) + { + m_part = + "uniform sampler2D uTex0; \n" + "uniform sampler2D uTex1; \n" + "uniform lowp vec4 uFogColor; \n" + "uniform lowp vec4 uCenterColor;\n" + "uniform lowp vec4 uScaleColor; \n" + "uniform lowp vec4 uBlendColor; \n" + "uniform lowp vec4 uEnvColor; \n" + "uniform lowp vec4 uPrimColor; \n" + "uniform lowp float uPrimLod; \n" + "uniform lowp float uK4; \n" + "uniform lowp float uK5; \n" + "uniform lowp int uAlphaCompareMode; \n" + "uniform lowp ivec2 uFbMonochrome; \n" + "uniform lowp ivec2 uFbFixedAlpha; \n" + "uniform lowp int uEnableAlphaTest; \n" + "uniform lowp int uCvgXAlpha; \n" + "uniform lowp int uAlphaCvgSel; \n" + "uniform lowp float uAlphaTestValue; \n" + "uniform lowp int uDepthSource; \n" + "uniform highp float uPrimDepth; \n" + "uniform mediump vec2 uScreenScale; \n" + "uniform highp vec4 uTexClamp0; \n" + "uniform highp vec4 uTexClamp1; \n" + "uniform highp vec2 uTexWrap0; \n" + "uniform highp vec2 uTexWrap1; \n" + "uniform lowp vec2 uTexMirror0; \n" + "uniform lowp vec2 uTexMirror1; \n" + "uniform highp vec2 uTexScale0; \n" + "uniform highp vec2 uTexScale1; \n" + "uniform highp vec2 uTexCoordOffset[2]; \n" + "uniform lowp int uUseTexCoordBounds; \n" + "uniform highp vec4 uTexCoordBounds0; \n" + "uniform highp vec4 uTexCoordBounds1; \n" + "uniform lowp int uScreenSpaceTriangle; \n" + "highp vec2 texCoord0; \n" + "highp vec2 texCoord1; \n" + "uniform lowp int uCvgDest; \n" + "uniform lowp int uBlendAlphaMode; \n" + "lowp float cvg; \n" + ; + + if (config.generalEmulation.enableLegacyBlending != 0) { + m_part += + "uniform lowp int uFogUsage; \n" + ; + } else { + m_part += + "uniform lowp ivec4 uBlendMux1; \n" + "uniform lowp int uForceBlendCycle1;\n" + ; + } + + if (!_glinfo.isGLES2) { + m_part += + "uniform sampler2D uDepthTex; \n" + "uniform lowp int uAlphaDitherMode; \n" + "uniform lowp int uColorDitherMode; \n" + "uniform lowp int uRenderTarget; \n" + "uniform mediump vec2 uDepthScale; \n" + ; + if (config.frameBufferEmulation.N64DepthCompare != Config::dcDisable) { + m_part += + "uniform lowp int uEnableDepthCompare; \n" + ; + } + } else { + m_part += + "lowp int nCurrentTile; \n" + ; + } + + if (config.video.multisampling > 0) { + m_part += + "uniform lowp ivec2 uMSTexEnabled; \n" + "uniform lowp sampler2DMS uMSTex0; \n" + "uniform lowp sampler2DMS uMSTex1; \n" + ; + } + + if (!_glinfo.isGLESX || _glinfo.noPerspective) + m_part += "noperspective IN lowp vec4 vShadeColorNoperspective; \n"; + else + m_part += "IN lowp vec4 vShadeColorNoperspective; \n"; + + m_part += + "IN lowp vec4 vShadeColor; \n" + "IN highp vec2 vTexCoord0; \n" + "IN highp vec2 vTexCoord1; \n" + "IN mediump vec2 vLodTexCoord; \n" + "IN lowp float vNumLights; \n" + "IN highp vec4 vBaryCoords; \n" + ; + + if (_glinfo.dual_source_blending) { + m_part += + "layout(location = 0, index = 0) OUT lowp vec4 fragColor; \n" // MAIN FRAGMENT SHADER OUTPUT + "layout(location = 0, index = 1) OUT lowp vec4 fragColor1; \n" // SECONDARY FRAGMENT SHADER OUTPUT + "#define LAST_FRAG_COLOR vec4(0.0) \n" // DUMMY + "#define LAST_FRAG_ALPHA 1.0 \n" // DUMMY + ; + } else if (_glinfo.ext_fetch) { + m_part += + "layout(location = 0) inout lowp vec4 fragColor; \n" // MAIN FRAGMENT SHADER OUTPUT + "lowp vec4 fragColor1; \n" // DUMMY + "#define LAST_FRAG_COLOR fragColor \n" // CURRENT FRAMEBUFFER COLOR/ALPHA + "#define LAST_FRAG_ALPHA fragColor.a \n" // CURRENT FRAMEBUFFER ALPHA + ; + } else if (_glinfo.ext_fetch_arm) { + m_part += + "OUT lowp vec4 fragColor; \n" // MAIN FRAGMENT SHADER OUTPUT + "lowp vec4 fragColor1; \n" // DUMMY + "#define LAST_FRAG_COLOR gl_LastFragColorARM \n" // CURRENT FRAMEBUFFER COLOR/ALPHA + "#define LAST_FRAG_ALPHA gl_LastFragColorARM.a \n" // CURRENT FRAMEBUFFER ALPHA + ; + } else { + m_part += + "OUT lowp vec4 fragColor; \n" // MAIN FRAGMENT SHADER OUTPUT + "lowp vec4 fragColor1; \n" // DUMMY + "#define LAST_FRAG_COLOR vec4(0.0) \n" // DUMMY + "#define LAST_FRAG_ALPHA 1.0 \n" // DUMMY + ; + } + + if (config.frameBufferEmulation.N64DepthCompare == Config::dcFast && _glinfo.n64DepthWithFbFetch) { + m_part += + "layout(location = 1) inout highp vec4 depthZ; \n" + "layout(location = 2) inout highp vec4 depthDeltaZ; \n" + ; + } + } +}; + +class ShaderFragmentHeaderClampWrapMirror : public ShaderPart +{ +public: + ShaderFragmentHeaderClampWrapMirror(const opengl::GLInfo & _glinfo) + { + m_part = + "highp vec2 clampWrapMirror(in highp vec2 vTexCoord, \n" + " in highp vec4 vClamp, in highp vec2 vWrap, \n" + " in lowp vec2 vMirror, in highp vec2 vOffset); \n" + ; + } +}; + +class ShaderFragmentHeaderReadMSTexFast : public ShaderPart +{ +public: + ShaderFragmentHeaderReadMSTexFast(const opengl::GLInfo & _glinfo) : m_glinfo(_glinfo) + { + } + + void write(std::stringstream & shader) const override + { + if (!m_glinfo.isGLES2 && + config.video.multisampling > 0 && + (CombinerProgramBuilder::s_cycleType == G_CYC_COPY || CombinerProgramBuilder::s_textureConvert.useTextureFiltering())) + { + shader << + "lowp vec4 readTexMS(in lowp sampler2DMS mstex, in highp vec2 texCoord, in lowp int fbMonochrome, in lowp int fbFixedAlpha);\n"; + } + } + +private: + const opengl::GLInfo& m_glinfo; +}; + +class ShaderFragmentHeaderReadTexFast : public ShaderPart +{ +public: + ShaderFragmentHeaderReadTexFast(const opengl::GLInfo & _glinfo) : m_glinfo(_glinfo) + { + } + + void write(std::stringstream & shader) const override + { + std::string shaderPart; + if (!m_glinfo.isGLES2) { + + if (CombinerProgramBuilder::s_textureConvert.useTextureFiltering()) { + shaderPart += "uniform lowp int uTextureFilterMode; \n"; + switch (config.texture.bilinearMode + config.texture.enableHalosRemoval * 2) { + case BILINEAR_3POINT: + // 3 point texture filtering. + // Original author: ArthurCarvalho + // GLSL implementation: twinaphex, mupen64plus-libretro project. + shaderPart += + "#define TEX_OFFSET(off, tex, texCoord) texture(tex, texCoord - (off)/texSize) \n" + "#define TEX_FILTER(name, tex, texCoord) \\\n" + " { \\\n" + " mediump vec2 texSize = vec2(textureSize(tex,0)); \\\n" + " mediump vec2 offset = fract(texCoord*texSize - vec2(0.5)); \\\n" + " offset -= step(1.0, offset.x + offset.y); \\\n" + " lowp vec4 c0 = TEX_OFFSET(offset, tex, texCoord); \\\n" + " lowp vec4 c1 = TEX_OFFSET(vec2(offset.x - sign(offset.x), offset.y), tex, texCoord); \\\n" + " lowp vec4 c2 = TEX_OFFSET(vec2(offset.x, offset.y - sign(offset.y)), tex, texCoord); \\\n" + " name = c0 + abs(offset.x)*(c1-c0) + abs(offset.y)*(c2-c0); \\\n" + " } \n" + ; + break; + case BILINEAR_STANDARD: + shaderPart += + "#define TEX_OFFSET(off, tex, texCoord) texture(tex, texCoord - (off)/texSize) \n" + "#define TEX_FILTER(name, tex, texCoord) \\\n" + "{ \\\n" + " mediump vec2 texSize = vec2(textureSize(tex,0)); \\\n" + " mediump vec2 offset = fract(texCoord*texSize - vec2(0.5)); \\\n" + " offset -= step(1.0, offset.x + offset.y); \\\n" + " lowp vec4 zero = vec4(0.0); \\\n" + " \\\n" + " lowp vec4 p0q0 = TEX_OFFSET(offset, tex, texCoord); \\\n" + " lowp vec4 p1q0 = TEX_OFFSET(vec2(offset.x - sign(offset.x), offset.y), tex, texCoord); \\\n" + " \\\n" + " lowp vec4 p0q1 = TEX_OFFSET(vec2(offset.x, offset.y - sign(offset.y)), tex, texCoord); \\\n" + " lowp vec4 p1q1 = TEX_OFFSET(vec2(offset.x - sign(offset.x), offset.y - sign(offset.y)), tex, texCoord); \\\n" + " \\\n" + " mediump vec2 interpolationFactor = abs(offset); \\\n" + " lowp vec4 pInterp_q0 = mix( p0q0, p1q0, interpolationFactor.x ); \\\n" // Interpolates top row in X direction. + " lowp vec4 pInterp_q1 = mix( p0q1, p1q1, interpolationFactor.x ); \\\n" // Interpolates bottom row in X direction. + " name = mix( pInterp_q0, pInterp_q1, interpolationFactor.y ); \\\n" // Interpolate in Y direction. + "} \n" + ; + break; + case BILINEAR_3POINT_WITH_COLOR_BLEEDING: + // 3 point texture filtering. + // Original author: ArthurCarvalho + // GLSL implementation: twinaphex, mupen64plus-libretro project. + shaderPart += + "#define TEX_OFFSET(off, tex, texCoord) texture(tex, texCoord - (off)/texSize) \n" + "#define TEX_FILTER(name, tex, texCoord) \\\n" + "{ \\\n" + " mediump vec2 texSize = vec2(textureSize(tex,0)); \\\n" + " mediump vec2 offset = fract(texCoord*texSize - vec2(0.5)); \\\n" + " offset -= step(1.0, offset.x + offset.y); \\\n" + " lowp vec4 c0 = TEX_OFFSET(offset, tex, texCoord); \\\n" + " lowp vec4 c1 = TEX_OFFSET(vec2(offset.x - sign(offset.x), offset.y), tex, texCoord); \\\n" + " lowp vec4 c2 = TEX_OFFSET(vec2(offset.x, offset.y - sign(offset.y)), tex, texCoord); \\\n" + " \\\n" + " if(uEnableAlphaTest == 1 ){ \\\n" // Calculate premultiplied color values + " c0.rgb *= c0.a; \\\n" + " c1.rgb *= c1.a; \\\n" + " c2.rgb *= c2.a; \\\n" + " name = c0 + abs(offset.x)*(c1-c0) + abs(offset.y)*(c2-c0); \\\n" + " name.rgb /= name.a; \\\n" // Divide alpha to get actual color value + " } \\\n" + " else name = c0 + abs(offset.x)*(c1-c0) + abs(offset.y)*(c2-c0); \\\n" + "} \n" + ; + break; + case BILINEAR_STANDARD_WITH_COLOR_BLEEDING_AND_PREMULTIPLIED_ALPHA: + shaderPart += + "#define TEX_OFFSET(off, tex, texCoord) texture(tex, texCoord - (off)/texSize) \n" + "#define TEX_FILTER(name, tex, texCoord) \\\n" + "{ \\\n" + " mediump vec2 texSize = vec2(textureSize(tex,0)); \\\n" + " mediump vec2 offset = fract(texCoord*texSize - vec2(0.5)); \\\n" + " offset -= step(1.0, offset.x + offset.y); \\\n" + " lowp vec4 zero = vec4(0.0); \\\n" + " \\\n" + " lowp vec4 p0q0 = TEX_OFFSET(offset, tex, texCoord); \\\n" + " lowp vec4 p1q0 = TEX_OFFSET(vec2(offset.x - sign(offset.x), offset.y), tex, texCoord); \\\n" + " \\\n" + " lowp vec4 p0q1 = TEX_OFFSET(vec2(offset.x, offset.y - sign(offset.y)), tex, texCoord); \\\n" + " lowp vec4 p1q1 = TEX_OFFSET(vec2(offset.x - sign(offset.x), offset.y - sign(offset.y)), tex, texCoord); \\\n" + " \\\n" + " if(uEnableAlphaTest == 1){ \\\n" // Calculate premultiplied color values + " p0q0.rgb *= p0q0.a; \\\n" + " p1q0.rgb *= p1q0.a; \\\n" + " p0q1.rgb *= p0q1.a; \\\n" + " p1q1.rgb *= p1q1.a; \\\n" + " \\\n" + " mediump vec2 interpolationFactor = abs(offset); \\\n" + " lowp vec4 pInterp_q0 = mix( p0q0, p1q0, interpolationFactor.x ); \\\n" // Interpolates top row in X direction. + " lowp vec4 pInterp_q1 = mix( p0q1, p1q1, interpolationFactor.x ); \\\n" // Interpolates bottom row in X direction. + " name = mix( pInterp_q0, pInterp_q1, interpolationFactor.y ); \\\n" // Interpolate in Y direction. + " name.rgb /= name.a; \\\n" // Divide alpha to get actual color value + " } \\\n" + " else if(uCvgXAlpha == 1){ \\\n" // Use texture bleeding for mk64 + " if(p0q0.a > p1q0.a) p1q0.rgb = p0q0.rgb; \\\n" + " if(p1q0.a > p0q0.a) p0q0.rgb = p1q0.rgb; \\\n" + " if(p0q1.a > p1q1.a) p1q1.rgb = p0q1.rgb; \\\n" + " if(p1q1.a > p0q1.a) p0q1.rgb = p1q1.rgb; \\\n" + " if(p0q0.a > p0q1.a) p0q1.rgb = p0q0.rgb; \\\n" + " if(p0q1.a > p0q0.a) p0q0.rgb = p0q1.rgb; \\\n" + " if(p1q0.a > p1q1.a) p1q1.rgb = p1q0.rgb; \\\n" + " if(p1q1.a > p1q0.a) p1q0.rgb = p1q1.rgb; \\\n" + " \\\n" + " mediump vec2 interpolationFactor = abs(offset); \\\n" + " lowp vec4 pInterp_q0 = mix( p0q0, p1q0, interpolationFactor.x ); \\\n" // Interpolates top row in X direction. + " lowp vec4 pInterp_q1 = mix( p0q1, p1q1, interpolationFactor.x ); \\\n" // Interpolates bottom row in X direction. + " name = mix( pInterp_q0, pInterp_q1, interpolationFactor.y ); \\\n" + " } \\\n" + " else{ \\\n" + " mediump vec2 interpolationFactor = abs(offset); \\\n" + " lowp vec4 pInterp_q0 = mix( p0q0, p1q0, interpolationFactor.x ); \\\n" // Interpolates top row in X direction. + " lowp vec4 pInterp_q1 = mix( p0q1, p1q1, interpolationFactor.x ); \\\n" // Interpolates bottom row in X direction. + " name = mix( pInterp_q0, pInterp_q1, interpolationFactor.y ); \\\n" // Interpolate in Y direction. + " } \\\n" + "} \n" + ; + break; + } + shaderPart += + "#define READ_TEX(name, tex, texCoord, fbMonochrome, fbFixedAlpha) \\\n" + " { \\\n" + " if (fbMonochrome == 3) { \\\n" + " mediump ivec2 coord = ivec2(gl_FragCoord.xy); \\\n" + " name = texelFetch(tex, coord, 0); \\\n" + " } else { \\\n" + " if (uTextureFilterMode == 0) name = texture(tex, texCoord); \\\n" + " else TEX_FILTER(name, tex, texCoord); \\\n" + " } \\\n" + " if (fbMonochrome == 1) name = vec4(name.r); \\\n" + " else if (fbMonochrome == 2) \\\n" + " name.rgb = vec3(dot(vec3(0.2126, 0.7152, 0.0722), name.rgb)); \\\n" + " else if (fbMonochrome == 3) { \\\n" + " name.rgb = vec3(dot(vec3(0.2126, 0.7152, 0.0722), name.rgb)); \\\n" + " name.a = 0.0; \\\n" + " } \\\n" + " if (fbFixedAlpha == 1) name.a = 0.825; \\\n" + " } \n" + ; + } + + if (CombinerProgramBuilder::s_textureConvert.useYUVCoversion()) { + shaderPart += + "uniform lowp ivec2 uTextureFormat; \n" + "uniform lowp int uTextureConvert; \n" + "uniform mediump ivec4 uConvertParams; \n" + "#define YUVCONVERT(name, format) \\\n" + " mediump ivec4 icolor = ivec4(name*255.0); \\\n" + " if (format == 1) \\\n" + " icolor.rg -= 128; \\\n" + " mediump ivec4 iconvert; \\\n" + " iconvert.r = icolor.b + (uConvertParams[0]*icolor.g + 128)/256; \\\n" + " iconvert.g = icolor.b + (uConvertParams[1]*icolor.r + uConvertParams[2]*icolor.g + 128)/256; \\\n" + " iconvert.b = icolor.b + (uConvertParams[3]*icolor.r + 128)/256; \\\n" + " iconvert.a = icolor.b; \\\n" + " name = vec4(iconvert)/255.0; \n" + "#define YUVCONVERT_TEX0(name, tex, texCoord, format) \\\n" + " { \\\n" + " name = texture(tex, texCoord); \\\n" + " YUVCONVERT(name, format) \\\n" + " } \n" + "#define YUVCONVERT_TEX1(name, tex, texCoord, format, prev) \\\n" + " { \\\n" + " if (uTextureConvert != 0) name = prev; \\\n" + " else name = texture(tex, texCoord); \\\n" + " YUVCONVERT(name, format) \\\n" + " } \n" + ; + } + + } else { + if (CombinerProgramBuilder::s_textureConvert.useTextureFiltering()) { + shaderPart += + "uniform lowp int uTextureFilterMode; \n" + "lowp vec4 readTex(in sampler2D tex, in highp vec2 texCoord, in lowp int fbMonochrome, in lowp int fbFixedAlpha); \n" + ; + } + if (CombinerProgramBuilder::s_textureConvert.useYUVCoversion()) { + shaderPart += + "uniform lowp ivec2 uTextureFormat; \n" + "uniform lowp int uTextureConvert; \n" + "uniform mediump ivec4 uConvertParams; \n" + "lowp vec4 YUV_Convert(in sampler2D tex, in highp vec2 texCoord, in lowp int convert, in lowp int format, in lowp vec4 prev); \n" + ; + } + } + + shader << shaderPart; + } + +private: + const opengl::GLInfo& m_glinfo; +}; + +class ShaderFragmentHeaderReadTexCopyModeFast : public ShaderPart +{ +public: + ShaderFragmentHeaderReadTexCopyModeFast (const opengl::GLInfo & _glinfo) + { + if (!_glinfo.isGLES2) { + m_part = + "#define READ_TEX(name, tex, texCoord, fbMonochrome, fbFixedAlpha) \\\n" + " { \\\n" + " if (fbMonochrome == 3) { \\\n" + " mediump ivec2 coord = ivec2(gl_FragCoord.xy); \\\n" + " name = texelFetch(tex, coord, 0); \\\n" + " } else { \\\n" + " name = texture(tex, texCoord); \\\n" + " } \\\n" + " if (fbMonochrome == 1) name = vec4(name.r); \\\n" + " else if (fbMonochrome == 2) \\\n" + " name.rgb = vec3(dot(vec3(0.2126, 0.7152, 0.0722), name.rgb)); \\\n" + " else if (fbMonochrome == 3) { \\\n" + " name.rgb = vec3(dot(vec3(0.2126, 0.7152, 0.0722), name.rgb)); \\\n" + " name.a = 0.0; \\\n" + " } \\\n" + " if (fbFixedAlpha == 1) name.a = 0.825; \\\n" + " } \n" + ; + } else { + m_part = + "lowp vec4 readTex(in sampler2D tex, in highp vec2 texCoord, in lowp int fbMonochrome, in lowp int fbFixedAlpha); \n" + ; + } + } +}; + +class ShaderFragmentClampWrapMirrorTex0 : public ShaderPart +{ +public: + ShaderFragmentClampWrapMirrorTex0(const opengl::GLInfo & _glinfo) + { + m_part = + " texCoord0 = clampWrapMirror(vTexCoord0, uTexClamp0, uTexWrap0, uTexMirror0, uTexScale0); \n" + ; + } +}; + +class ShaderFragmentClampWrapMirrorTex1 : public ShaderPart +{ +public: + ShaderFragmentClampWrapMirrorTex1(const opengl::GLInfo & _glinfo) + { + m_part = + " texCoord1 = clampWrapMirror(vTexCoord1, uTexClamp1, uTexWrap1, uTexMirror1, uTexScale1); \n" + ; + } +}; + +class ShaderFragmentReadTexCopyModeFast : public ShaderPart +{ +public: + ShaderFragmentReadTexCopyModeFast(const opengl::GLInfo & _glinfo) + { + if (_glinfo.isGLES2) { + m_part = + " nCurrentTile = 0; \n" + " lowp vec4 readtex0 = readTex(uTex0, texCoord0, uFbMonochrome[0], uFbFixedAlpha[0]); \n" + ; + } else { + if (config.video.multisampling > 0) { + m_part = + " lowp vec4 readtex0; \n" + " if (uMSTexEnabled[0] == 0) { \n" + " READ_TEX(readtex0, uTex0, texCoord0, uFbMonochrome[0], uFbFixedAlpha[0]) \n" + " } else readtex0 = readTexMS(uMSTex0, texCoord0, uFbMonochrome[0], uFbFixedAlpha[0]);\n" + ; + } else { + m_part = + " lowp vec4 readtex0; \n" + " READ_TEX(readtex0, uTex0, texCoord0, uFbMonochrome[0], uFbFixedAlpha[0]) \n" + ; + } + } + } +}; + +class ShaderFragmentReadTex0Fast : public ShaderPart +{ +public: + ShaderFragmentReadTex0Fast(const opengl::GLInfo & _glinfo) : m_glinfo(_glinfo) + { + } + + void write(std::stringstream & shader) const override + { + std::string shaderPart; + + if (m_glinfo.isGLES2) { + + shaderPart = " nCurrentTile = 0; \n"; + if (CombinerProgramBuilder::s_textureConvert.getBilerp0()) { + shaderPart += " lowp vec4 readtex0 = readTex(uTex0, texCoord0, uFbMonochrome[0], uFbFixedAlpha[0]); \n"; + } else { + shaderPart += " lowp vec4 tmpTex = vec4(0.0); \n" + " lowp vec4 readtex0 = YUV_Convert(uTex0, texCoord0, 0, uTextureFormat[0], tmpTex); \n"; + } + + } else { + + if (!CombinerProgramBuilder::s_textureConvert.getBilerp0()) { + shaderPart = " lowp vec4 readtex0; \n" + " YUVCONVERT_TEX0(readtex0, uTex0, texCoord0, uTextureFormat[0]) \n"; + } else { + if (config.video.multisampling > 0) { + shaderPart = + " lowp vec4 readtex0; \n" + " if (uMSTexEnabled[0] == 0) { \n" + " READ_TEX(readtex0, uTex0, texCoord0, uFbMonochrome[0], uFbFixedAlpha[0]) \n" + " } else readtex0 = readTexMS(uMSTex0, texCoord0, uFbMonochrome[0], uFbFixedAlpha[0]); \n"; + } else { + shaderPart = " lowp vec4 readtex0; \n" + " READ_TEX(readtex0, uTex0, texCoord0, uFbMonochrome[0], uFbFixedAlpha[0]) \n"; + } + } + + } + + shader << shaderPart; + } + +private: + const opengl::GLInfo& m_glinfo; +}; + +class ShaderFragmentReadTex1Fast : public ShaderPart +{ +public: + ShaderFragmentReadTex1Fast(const opengl::GLInfo & _glinfo) : m_glinfo(_glinfo) + { + } + + void write(std::stringstream & shader) const override + { + std::string shaderPart; + + if (m_glinfo.isGLES2) { + + shaderPart = " nCurrentTile = 1; \n"; + + if (CombinerProgramBuilder::s_textureConvert.getBilerp1()) { + shaderPart += " lowp vec4 readtex1 = readTex(uTex1, texCoord1, uFbMonochrome[1], uFbFixedAlpha[1]); \n"; + } else { + shaderPart += " lowp vec4 readtex1 = YUV_Convert(uTex1, texCoord1, uTextureConvert, uTextureFormat[1], readtex0); \n"; + } + + } else { + + if (!CombinerProgramBuilder::s_textureConvert.getBilerp1()) { + shaderPart = + " lowp vec4 readtex1; \n" + " YUVCONVERT_TEX1(readtex1, uTex1, texCoord1, uTextureFormat[1], readtex0) \n"; + } else { + if (config.video.multisampling > 0) { + shaderPart = + " lowp vec4 readtex1; \n" + " if (uMSTexEnabled[1] == 0) { \n" + " READ_TEX(readtex1, uTex1, texCoord1, uFbMonochrome[1], uFbFixedAlpha[1]) \n" + " } else readtex1 = readTexMS(uMSTex1, texCoord1, uFbMonochrome[1], uFbFixedAlpha[1]); \n"; + } else { + shaderPart = " lowp vec4 readtex1; \n" + " READ_TEX(readtex1, uTex1, texCoord1, uFbMonochrome[1], uFbFixedAlpha[1]) \n"; + } + } + + } + + shader << shaderPart; + } + +private: + const opengl::GLInfo& m_glinfo; +}; + +class ShaderMipmapFast : public ShaderPart +{ +public: + ShaderMipmapFast(const opengl::GLInfo & _glinfo) + { + if (_glinfo.isGLES2) { + if (config.generalEmulation.enableLOD == 0) { + // Fake mipmap + m_part = + "uniform lowp int uMaxTile; \n" + "uniform mediump float uMinLod; \n" + " \n" + "mediump float mipmap(out lowp vec4 readtex0, out lowp vec4 readtex1) { \n" + " readtex0 = texture2D(uTex0, texCoord0); \n" + " readtex1 = texture2D(uTex1, texCoord1); \n" + " if (uMaxTile == 0) return 1.0; \n" + " return uMinLod; \n" + "} \n" + ; + } else { + m_part = + "uniform lowp int uEnableLod; \n" + "uniform mediump float uMinLod; \n" + "uniform lowp int uMaxTile; \n" + "uniform lowp int uTextureDetail; \n" + " \n" + "mediump float mipmap(out lowp vec4 readtex0, out lowp vec4 readtex1) { \n" + " readtex0 = texture2D(uTex0, texCoord0); \n" + " readtex1 = texture2DLodEXT(uTex1, texCoord1, 0.0); \n" + " \n" + " mediump float fMaxTile = float(uMaxTile); \n" + " mediump vec2 dx = abs(dFdx(vLodTexCoord)) * uScreenScale; \n" + " mediump vec2 dy = abs(dFdy(vLodTexCoord)) * uScreenScale; \n" + " mediump float lod = max(dx.x + dx.y, dy.x + dy.y); \n" /*LINEAR*/ + " bool magnify = lod < 1.0; \n" + " mediump float lod_tile = magnify ? 0.0 : floor(log2(floor(lod))); \n" + " bool distant = lod > 128.0 || lod_tile >= fMaxTile; \n" + " mediump float lod_frac = fract(lod/pow(2.0, lod_tile)); \n" + " if (magnify) lod_frac = max(lod_frac, uMinLod); \n" + " if (uTextureDetail == 0) { \n" + " if (distant) lod_frac = 1.0; \n" + " else if (magnify) lod_frac = 0.0; \n" + " } \n" + " if (magnify && (uTextureDetail == 1 || uTextureDetail == 3)) \n" + " lod_frac = 1.0 - lod_frac; \n" + " if (uMaxTile == 0) { \n" + " if (uEnableLod != 0) { \n" + " if (uTextureDetail < 2) readtex1 = readtex0; \n" + " else if (!magnify) readtex0 = readtex1; \n" + " } \n" + " return lod_frac; \n" + " } \n" + " if (uEnableLod == 0) return lod_frac; \n" + " \n" + " lod_tile = min(lod_tile, fMaxTile); \n" + " lowp float lod_tile_m1 = max(0.0, lod_tile - 1.0); \n" + " lowp float lod_tile_p1 = min(fMaxTile - 1.0, lod_tile + 1.0); \n" + " lowp vec4 lodT = texture2DLodEXT(uTex1, texCoord1, lod_tile); \n" + " lowp vec4 lodT_m1 = texture2DLodEXT(uTex1, texCoord1, lod_tile_m1); \n" + " lowp vec4 lodT_p1 = texture2DLodEXT(uTex1, texCoord1, lod_tile_p1); \n" + " if (lod_tile < 1.0) { \n" + " if (magnify) { \n" + // !sharpen && !detail + " if (uTextureDetail == 0) readtex1 = readtex0; \n" + " } else { \n" + // detail + " if (uTextureDetail > 1) { \n" + " readtex0 = lodT; \n" + " readtex1 = lodT_p1; \n" + " } \n" + " } \n" + " } else { \n" + " if (uTextureDetail > 1) { \n" + " readtex0 = lodT; \n" + " readtex1 = lodT_p1; \n" + " } else { \n" + " readtex0 = lodT_m1; \n" + " readtex1 = lodT; \n" + " } \n" + " } \n" + " return lod_frac; \n" + "} \n" + ; + } + } + else { + if (config.generalEmulation.enableLOD == 0) { + // Fake mipmap + m_part = + "uniform lowp int uMaxTile; \n" + "uniform mediump float uMinLod; \n" + " \n" + "mediump float mipmap(out lowp vec4 readtex0, out lowp vec4 readtex1) { \n" + " readtex0 = texture(uTex0, texCoord0); \n" + " readtex1 = texture(uTex1, texCoord1); \n" + " if (uMaxTile == 0) return 1.0; \n" + " return uMinLod; \n" + "} \n" + ; + } else { + if (config.texture.bilinearMode == BILINEAR_3POINT) + m_part = + "#define TEX_OFFSET_NORMAL(off, tex, texCoord, lod) texture(tex, texCoord - (off)/texSize) \n" + "#define TEX_OFFSET_MIPMAP(off, tex, texCoord, lod) textureLod(tex, texCoord - (off)/texSize, lod) \n" + "#define READ_TEX_NORMAL(name, tex, texCoord, lod) \\\n" + " { \\\n" + " mediump vec2 texSize = vec2(textureSize(tex, int(lod))); \\\n" + " mediump vec2 offset = fract(texCoord*texSize - vec2(0.5)); \\\n" + " offset -= step(1.0, offset.x + offset.y); \\\n" + " lowp vec4 c0 = TEX_OFFSET_NORMAL(offset, tex, texCoord, lod); \\\n" + " lowp vec4 c1 = TEX_OFFSET_NORMAL(vec2(offset.x - sign(offset.x), offset.y), tex, texCoord, lod); \\\n" + " lowp vec4 c2 = TEX_OFFSET_NORMAL(vec2(offset.x, offset.y - sign(offset.y)), tex, texCoord, lod); \\\n" + " name = c0 + abs(offset.x)*(c1-c0) + abs(offset.y)*(c2-c0); \\\n" + " } \n" + "#define READ_TEX_MIPMAP(name, tex, texCoord, lod) \\\n" + " { \\\n" + " mediump vec2 texSize = vec2(textureSize(tex, int(lod))); \\\n" + " mediump vec2 offset = fract(texCoord*texSize - vec2(0.5)); \\\n" + " offset -= step(1.0, offset.x + offset.y); \\\n" + " lowp vec4 c0 = TEX_OFFSET_MIPMAP(offset, tex, texCoord, lod); \\\n" + " lowp vec4 c1 = TEX_OFFSET_MIPMAP(vec2(offset.x - sign(offset.x), offset.y), tex, texCoord, lod); \\\n" + " lowp vec4 c2 = TEX_OFFSET_MIPMAP(vec2(offset.x, offset.y - sign(offset.y)), tex, texCoord, lod); \\\n" + " name = c0 + abs(offset.x)*(c1-c0) + abs(offset.y)*(c2-c0); \\\n" + " } \n" + ; + else + m_part = + "#define TEX_FETCH_NORMAL(tex, texCoord, lod) texture(tex, texCoord) \n" + "#define TEX_FETCH_MIPMAP(tex, texCoord, lod) textureLod(tex, texCoord, lod) \n" + "#define READ_TEX_NORMAL(name, tex, texCoord, lod) name = TEX_FETCH_NORMAL(tex, texCoord, lod) \n" + "#define READ_TEX_MIPMAP(name, tex, texCoord, lod) name = TEX_FETCH_MIPMAP(tex, texCoord, lod) \n" + ; + m_part += + "uniform lowp int uEnableLod; \n" + "uniform mediump float uMinLod; \n" + "uniform lowp int uMaxTile; \n" + "uniform lowp int uTextureDetail; \n" + " \n" + "mediump float mipmap(out lowp vec4 readtex0, out lowp vec4 readtex1) { \n" + " READ_TEX_NORMAL(readtex0, uTex0, texCoord0, 0.0); \n" + " READ_TEX_MIPMAP(readtex1, uTex1, texCoord1, 0.0); \n" + " \n" + " mediump float fMaxTile = float(uMaxTile); \n" + " mediump vec2 dx = abs(dFdx(vLodTexCoord)); \n" + " dx *= uScreenScale; \n" + " mediump float lod = max(dx.x, dx.y); \n" + " bool magnify = lod < 1.0; \n" + " mediump float lod_tile = magnify ? 0.0 : floor(log2(floor(lod))); \n" + " bool distant = lod > 128.0 || lod_tile >= fMaxTile; \n" + " mediump float lod_frac = fract(lod/pow(2.0, lod_tile)); \n" + " if (magnify) lod_frac = max(lod_frac, uMinLod); \n" + " if (uTextureDetail == 0) { \n" + " if (distant) lod_frac = 1.0; \n" + " else if (magnify) lod_frac = 0.0; \n" + " } \n" + " if (magnify && ((uTextureDetail & 1) != 0)) \n" + " lod_frac = 1.0 - lod_frac; \n" + " if (uMaxTile == 0) { \n" + " if (uEnableLod != 0) { \n" + " if ((uTextureDetail & 2) == 0) readtex1 = readtex0; \n" + " else if (!magnify) readtex0 = readtex1; \n" + " } \n" + " return lod_frac; \n" + " } \n" + " if (uEnableLod == 0) return lod_frac; \n" + " \n" + " lod_tile = min(lod_tile, fMaxTile - 1.0); \n" + " lowp float lod_tile_m1 = max(0.0, lod_tile - 1.0); \n" + " lowp float lod_tile_p1 = min(fMaxTile - 1.0, lod_tile + 1.0); \n" + " lowp vec4 lodT, lodT_m1, lodT_p1; \n" + " READ_TEX_MIPMAP(lodT, uTex1, texCoord1, lod_tile); \n" + " READ_TEX_MIPMAP(lodT_m1, uTex1, texCoord1, lod_tile_m1); \n" + " READ_TEX_MIPMAP(lodT_p1, uTex1, texCoord1, lod_tile_p1); \n" + " if (lod_tile < 1.0) { \n" + " if (magnify) { \n" + // !sharpen && !detail + " if (uTextureDetail == 0) readtex1 = readtex0; \n" + " } else { \n" + // detail + " if ((uTextureDetail & 2) != 0 ) { \n" + " readtex0 = lodT; \n" + " readtex1 = lodT_p1; \n" + " } \n" + " } \n" + " } else { \n" + " if ((uTextureDetail & 2) != 0 ) { \n" + " readtex0 = lodT; \n" + " readtex1 = lodT_p1; \n" + " } else { \n" + " readtex0 = lodT_m1; \n" + " readtex1 = lodT; \n" + " } \n" + " } \n" + " return lod_frac; \n" + "} \n" + ; + } + } + } +}; + +class ShaderReadtexFast : public ShaderPart +{ +public: + ShaderReadtexFast(const opengl::GLInfo & _glinfo) : m_glinfo(_glinfo) + { + } + + void write(std::stringstream & shader) const override + { + std::string shaderPart; + + if (m_glinfo.isGLES2) { + if (CombinerProgramBuilder::s_textureConvert.useYUVCoversion()) + shaderPart += + "lowp vec4 YUV_Convert(in sampler2D tex, in highp vec2 texCoord, in lowp int convert, in lowp int format, in lowp vec4 prev) \n" + "{ \n" + " lowp vec4 texColor; \n" + " if (convert != 0) texColor = prev; \n" + " else texColor = texture2D(tex, texCoord); \n" + " mediump ivec4 icolor = ivec4(texColor*255.0); \n" + " if (format == 1) \n" + " icolor.rg -= 128; \n" + " mediump ivec4 iconvert; \n" + " iconvert.r = icolor.b + (uConvertParams[0]*icolor.g + 128)/256; \n" + " iconvert.g = icolor.b + (uConvertParams[1]*icolor.r + uConvertParams[2]*icolor.g + 128)/256; \n" + " iconvert.b = icolor.b + (uConvertParams[3]*icolor.r + 128)/256; \n" + " iconvert.a = icolor.b; \n" + " return vec4(iconvert)/255.0; \n" + " } \n" + ; + if (CombinerProgramBuilder::s_textureConvert.useTextureFiltering()) { + if (config.texture.bilinearMode == BILINEAR_3POINT) { + shaderPart += + "uniform mediump vec2 uTextureSize[2]; \n" + // 3 point texture filtering. + // Original author: ArthurCarvalho + // GLSL implementation: twinaphex, mupen64plus-libretro project. + "#define TEX_OFFSET(off) texture2D(tex, texCoord - (off)/texSize) \n" + "lowp vec4 TextureFilter(in sampler2D tex, in highp vec2 texCoord) \n" + "{ \n" + " mediump vec2 texSize; \n" + " if (nCurrentTile == 0) \n" + " texSize = uTextureSize[0]; \n" + " else \n" + " texSize = uTextureSize[1]; \n" + " mediump vec2 offset = fract(texCoord*texSize - vec2(0.5)); \n" + " offset -= step(1.0, offset.x + offset.y); \n" + " lowp vec4 c0 = TEX_OFFSET(offset); \n" + " lowp vec4 c1 = TEX_OFFSET(vec2(offset.x - sign(offset.x), offset.y)); \n" + " lowp vec4 c2 = TEX_OFFSET(vec2(offset.x, offset.y - sign(offset.y))); \n" + " return c0 + abs(offset.x)*(c1-c0) + abs(offset.y)*(c2-c0); \n" + "} \n" + ; + } else { + shaderPart += + // bilinear filtering. + "uniform mediump vec2 uTextureSize[2]; \n" + "#define TEX_OFFSET(off) texture2D(tex, texCoord - (off)/texSize) \n" + "lowp vec4 TextureFilter(in sampler2D tex, in highp vec2 texCoord) \n" + "{ \n" + " mediump vec2 texSize; \n" + " if (nCurrentTile == 0) \n" + " texSize = uTextureSize[0]; \n" + " else \n" + " texSize = uTextureSize[1]; \n" + " mediump vec2 offset = fract(texCoord*texSize - vec2(0.5)); \n" + " offset -= step(1.0, offset.x + offset.y); \n" + " lowp vec4 zero = vec4(0.0); \n" + " \n" + " lowp vec4 p0q0 = TEX_OFFSET(offset); \n" + " lowp vec4 p1q0 = TEX_OFFSET(vec2(offset.x - sign(offset.x), offset.y)); \n" + " \n" + " lowp vec4 p0q1 = TEX_OFFSET(vec2(offset.x, offset.y - sign(offset.y))); \n" + " lowp vec4 p1q1 = TEX_OFFSET(vec2(offset.x - sign(offset.x), offset.y - sign(offset.y)));\n" + " \n" + " mediump vec2 interpolationFactor = abs(offset); \n" + " lowp vec4 pInterp_q0 = mix( p0q0, p1q0, interpolationFactor.x ); \n" // Interpolates top row in X direction. + " lowp vec4 pInterp_q1 = mix( p0q1, p1q1, interpolationFactor.x ); \n" // Interpolates bottom row in X direction. + " return mix( pInterp_q0, pInterp_q1, interpolationFactor.y ); \n" // Interpolate in Y direction. + "} \n" + ; + } + shaderPart += + "lowp vec4 readTex(in sampler2D tex, in highp vec2 texCoord, in lowp int fbMonochrome, in lowp int fbFixedAlpha) \n" + "{ \n" + " lowp vec4 texColor; \n" + " if (uTextureFilterMode == 0) texColor = texture2D(tex, texCoord); \n" + " else texColor = TextureFilter(tex, texCoord); \n" + " if (fbMonochrome == 1) texColor = vec4(texColor.r); \n" + " else if (fbMonochrome == 2) \n" + " texColor.rgb = vec3(dot(vec3(0.2126, 0.7152, 0.0722), texColor.rgb)); \n" + " if (fbFixedAlpha == 1) texColor.a = 0.825; \n" + " return texColor; \n" + "} \n" + ; + } + } else { + if (config.video.multisampling > 0 && CombinerProgramBuilder::s_textureConvert.useTextureFiltering()) { + shaderPart = + "uniform lowp int uMSAASamples; \n" + "lowp vec4 sampleMS(in lowp sampler2DMS mstex, in mediump ivec2 ipos) \n" + "{ \n" + " lowp vec4 texel = vec4(0.0); \n" + " for (int i = 0; i < uMSAASamples; ++i) \n" + " texel += texelFetch(mstex, ipos, i); \n" + " return texel / float(uMSAASamples); \n" + "} \n" + " \n" + "lowp vec4 readTexMS(in lowp sampler2DMS mstex, in highp vec2 texCoord, in lowp int fbMonochrome, in lowp int fbFixedAlpha) \n" + "{ \n" + " mediump ivec2 itexCoord; \n" + " if (fbMonochrome == 3) { \n" + " itexCoord = ivec2(gl_FragCoord.xy); \n" + " } else { \n" + " mediump vec2 msTexSize = vec2(textureSize(mstex)); \n" + " itexCoord = ivec2(msTexSize * texCoord); \n" + " } \n" + " lowp vec4 texColor = sampleMS(mstex, itexCoord); \n" + " if (fbMonochrome == 1) texColor = vec4(texColor.r); \n" + " else if (fbMonochrome == 2) \n" + " texColor.rgb = vec3(dot(vec3(0.2126, 0.7152, 0.0722), texColor.rgb)); \n" + " else if (fbMonochrome == 3) { \n" + " texColor.rgb = vec3(dot(vec3(0.2126, 0.7152, 0.0722), texColor.rgb)); \n" + " texColor.a = 0.0; \n" + " } \n" + " if (fbFixedAlpha == 1) texColor.a = 0.825; \n" + " return texColor; \n" + "} \n" + ; + } + } + + shader << shaderPart; + } + +private: + const opengl::GLInfo& m_glinfo; +}; + +class ShaderReadtexCopyModeFast : public ShaderPart +{ +public: + ShaderReadtexCopyModeFast(const opengl::GLInfo & _glinfo) + { + if (_glinfo.isGLES2) { + m_part = + "lowp vec4 readTex(in sampler2D tex, in highp vec2 texCoord, in lowp int fbMonochrome, in lowp int fbFixedAlpha) \n" + "{ \n" + " lowp vec4 texColor = texture2D(tex, texCoord); \n" + " if (fbMonochrome == 1) texColor = vec4(texColor.r); \n" + " else if (fbMonochrome == 2) \n" + " texColor.rgb = vec3(dot(vec3(0.2126, 0.7152, 0.0722), texColor.rgb)); \n" + " if (fbFixedAlpha == 1) texColor.a = 0.825; \n" + " return texColor; \n" + "} \n" + ; + } else { + if (config.video.multisampling > 0) { + m_part = + "uniform lowp int uMSAASamples; \n" + "lowp vec4 sampleMS(in lowp sampler2DMS mstex, in mediump ivec2 ipos) \n" + "{ \n" + " lowp vec4 texel = vec4(0.0); \n" + " for (int i = 0; i < uMSAASamples; ++i) \n" + " texel += texelFetch(mstex, ipos, i); \n" + " return texel / float(uMSAASamples); \n" + "} \n" + " \n" + "lowp vec4 readTexMS(in lowp sampler2DMS mstex, in highp vec2 texCoord, in lowp int fbMonochrome, in lowp int fbFixedAlpha) \n" + "{ \n" + " mediump ivec2 itexCoord; \n" + " if (fbMonochrome == 3) { \n" + " itexCoord = ivec2(gl_FragCoord.xy); \n" + " } else { \n" + " mediump vec2 msTexSize = vec2(textureSize(mstex)); \n" + " itexCoord = ivec2(msTexSize * texCoord); \n" + " } \n" + " lowp vec4 texColor = sampleMS(mstex, itexCoord); \n" + " if (fbMonochrome == 1) texColor = vec4(texColor.r); \n" + " else if (fbMonochrome == 2) \n" + " texColor.rgb = vec3(dot(vec3(0.2126, 0.7152, 0.0722), texColor.rgb)); \n" + " else if (fbMonochrome == 3) { \n" + " texColor.rgb = vec3(dot(vec3(0.2126, 0.7152, 0.0722), texColor.rgb)); \n" + " texColor.a = 0.0; \n" + " } \n" + " if (fbFixedAlpha == 1) texColor.a = 0.825; \n" + " return texColor; \n" + "} \n" + ; + } + } + } +}; + +class ShaderClampWrapMirror : public ShaderPart +{ +public: + ShaderClampWrapMirror(const opengl::GLInfo & _glinfo) + { + m_part = + "highp vec2 clampWrapMirror(in highp vec2 vTexCoord, in highp vec4 vClamp, \n" + " in highp vec2 vWrap, in lowp vec2 vMirror, in highp vec2 vScale) \n" + "{ \n" + " highp vec2 texCoord = clamp(vTexCoord, vClamp.xy, vClamp.zw); \n" + " lowp vec2 one = vec2(1.0); \n" + " lowp vec2 clamped = step(vClamp.zw, texCoord); \n" + " lowp vec2 notClamped = one - clamped; \n" + " lowp vec2 wrapped = step(vWrap , texCoord); \n" + " lowp vec2 notWrapped = one - wrapped; \n" + " texCoord = clamped * texCoord + notClamped * (wrapped*mod(texCoord, vWrap) + notWrapped*texCoord); \n" + " highp vec2 intPart = floor(texCoord); \n" + " highp vec2 fractPart = fract(texCoord); \n" + " lowp vec2 needMirror = step(vec2(0.5), mod(intPart, vWrap)) * vMirror; \n" + " texCoord = clamped * texCoord + notClamped * fractPart; \n" + " texCoord = (one - vMirror) * texCoord + vMirror * fractPart; \n" + " texCoord = (one - texCoord) * needMirror + texCoord * (one - needMirror); \n" + " texCoord *= vScale; \n" + " return texCoord; \n" + "} \n" + ; + } +}; + +CombinerProgramBuilderFast::CombinerProgramBuilderFast(const opengl::GLInfo & _glinfo, opengl::CachedUseProgram * _useProgram) +: CombinerProgramBuilderCommon(_glinfo, _useProgram, std::make_unique(_glinfo), + std::make_unique(_glinfo)) +, m_fragmentGlobalVariablesTex(new ShaderFragmentGlobalVariablesTexFast(_glinfo)) +, m_fragmentHeaderClampWrapMirror(new ShaderFragmentHeaderClampWrapMirror(_glinfo)) +, m_fragmentHeaderReadMSTex(new ShaderFragmentHeaderReadMSTexFast(_glinfo)) +, m_fragmentHeaderReadTex(new ShaderFragmentHeaderReadTexFast(_glinfo)) +, m_fragmentHeaderReadTexCopyMode(new ShaderFragmentHeaderReadTexCopyModeFast(_glinfo)) +, m_fragmentReadTex0(new ShaderFragmentReadTex0Fast(_glinfo)) +, m_fragmentReadTex1(new ShaderFragmentReadTex1Fast(_glinfo)) +, m_fragmentClampWrapMirrorTex0(new ShaderFragmentClampWrapMirrorTex0(_glinfo)) +, m_fragmentClampWrapMirrorTex1(new ShaderFragmentClampWrapMirrorTex1(_glinfo)) +, m_fragmentReadTexCopyMode(new ShaderFragmentReadTexCopyModeFast(_glinfo)) +, m_shaderMipmap(new ShaderMipmapFast(_glinfo)) +, m_shaderReadtex(new ShaderReadtexFast(_glinfo)) +, m_shaderReadtexCopyMode(new ShaderReadtexCopyModeFast(_glinfo)) +, m_shaderClampWrapMirror(new ShaderClampWrapMirror(_glinfo)) +{ + +} + +void CombinerProgramBuilderFast::_writeFragmentGlobalVariablesTex(std::stringstream& ssShader) const +{ + m_fragmentGlobalVariablesTex->write(ssShader); +} + +void CombinerProgramBuilderFast::_writeFragmentHeaderReadMSTex(std::stringstream& ssShader) const +{ + m_fragmentHeaderReadMSTex->write(ssShader); +} + +void CombinerProgramBuilderFast::_writeFragmentHeaderReadTex(std::stringstream& ssShader) const +{ + m_fragmentHeaderReadTex->write(ssShader); +} + +void CombinerProgramBuilderFast::_writeFragmentHeaderReadTexCopyMode(std::stringstream& ssShader) const +{ + m_fragmentHeaderReadTexCopyMode->write(ssShader); +} + +void CombinerProgramBuilderFast::_writeFragmentHeaderClampWrapMirrorEngine(std::stringstream& ssShader) const +{ + m_fragmentHeaderClampWrapMirror->write(ssShader); +} + +void CombinerProgramBuilderFast::_writeFragmentClampWrapMirrorEngineTex0(std::stringstream& ssShader) const +{ + m_fragmentClampWrapMirrorTex0->write(ssShader); +} + +void CombinerProgramBuilderFast::_writeFragmentClampWrapMirrorEngineTex1(std::stringstream& ssShader) const +{ + m_fragmentClampWrapMirrorTex1->write(ssShader); +} + +void CombinerProgramBuilderFast::_writeFragmentReadTex0(std::stringstream& ssShader) const +{ + m_fragmentReadTex0->write(ssShader); +} + +void CombinerProgramBuilderFast::_writeFragmentReadTex1(std::stringstream& ssShader) const +{ + m_fragmentReadTex1->write(ssShader); +} + +void CombinerProgramBuilderFast::_writeFragmentReadTexCopyMode(std::stringstream& ssShader) const +{ + m_fragmentReadTexCopyMode->write(ssShader); +} + +void CombinerProgramBuilderFast::_writeShaderClampWrapMirrorEngine(std::stringstream& ssShader) const +{ + m_shaderClampWrapMirror->write(ssShader); +} + +void CombinerProgramBuilderFast::_writeShaderMipmap(std::stringstream& ssShader) const +{ + m_shaderMipmap->write(ssShader); +} + +void CombinerProgramBuilderFast::_writeShaderReadtex(std::stringstream& ssShader) const +{ + m_shaderReadtex->write(ssShader); +} + +void CombinerProgramBuilderFast::_writeShaderReadtexCopyMode(std::stringstream& ssShader) const +{ + m_shaderReadtexCopyMode->write(ssShader); +} + + +} diff --git a/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilderFast.h b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilderFast.h new file mode 100644 index 00000000..cf343967 --- /dev/null +++ b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilderFast.h @@ -0,0 +1,47 @@ +#pragma once +#include + +namespace glsl { + +class CombinerProgramUniformFactory; + +class CombinerProgramBuilderFast : public glsl::CombinerProgramBuilderCommon +{ +public: + CombinerProgramBuilderFast(const opengl::GLInfo & _glinfo, opengl::CachedUseProgram * _useProgram); + +private: + + void _writeFragmentGlobalVariablesTex(std::stringstream& ssShader) const override; + void _writeFragmentHeaderReadMSTex(std::stringstream& ssShader) const override; + void _writeFragmentHeaderReadTex(std::stringstream& ssShader) const override; + void _writeFragmentHeaderReadTexCopyMode(std::stringstream& ssShader) const override; + void _writeFragmentHeaderClampWrapMirrorEngine(std::stringstream& ssShader) const override; + void _writeFragmentClampWrapMirrorEngineTex0(std::stringstream& ssShader) const override; + void _writeFragmentClampWrapMirrorEngineTex1(std::stringstream& ssShader) const override; + void _writeFragmentReadTex0(std::stringstream& ssShader) const override; + void _writeFragmentReadTex1(std::stringstream& ssShader) const override; + void _writeFragmentReadTexCopyMode(std::stringstream& ssShader) const override; + void _writeShaderClampWrapMirrorEngine(std::stringstream& ssShader) const override; + void _writeShaderMipmap(std::stringstream& ssShader) const override; + void _writeShaderReadtex(std::stringstream& ssShader) const override; + void _writeShaderReadtexCopyMode(std::stringstream& ssShader) const override; + + ShaderPartPtr m_fragmentGlobalVariablesTex; + ShaderPartPtr m_fragmentHeaderClampWrapMirror; + ShaderPartPtr m_fragmentHeaderReadMSTex; + ShaderPartPtr m_fragmentHeaderReadTex; + ShaderPartPtr m_fragmentHeaderReadTexCopyMode; + ShaderPartPtr m_fragmentReadTex0; + ShaderPartPtr m_fragmentReadTex1; + ShaderPartPtr m_fragmentClampWrapMirrorTex0; + ShaderPartPtr m_fragmentClampWrapMirrorTex1; + ShaderPartPtr m_fragmentReadTexCopyMode; + ShaderPartPtr m_shaderMipmap; + ShaderPartPtr m_shaderReadtex; + ShaderPartPtr m_shaderReadtexCopyMode; + ShaderPartPtr m_shaderClampWrapMirror; +}; + +} + diff --git a/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactory.cpp b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactory.cpp index def95ba6..bd71aa5b 100644 --- a/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactory.cpp +++ b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactory.cpp @@ -22,1274 +22,103 @@ namespace glsl { -/*---------------Uniform-------------*/ +CombinerProgramUniformFactory::CombinerProgramUniformFactory(const opengl::GLInfo &_glInfo) +: m_glInfo(_glInfo) { +} -struct iUniform { - GLint loc = -1; - int val = -999; - void set(int _val, bool _force) { - if (loc >= 0 && (_force || val != _val)) { - val = _val; - glUniform1i(loc, _val); - } - } -}; - -struct fUniform { - GLint loc = -1; - float val = -9999.9f; - void set(float _val, bool _force) { - if (loc >= 0 && (_force || val != _val)) { - val = _val; - glUniform1f(loc, _val); - } - } -}; - -struct fv2Uniform { - GLint loc = -1; - float val1 = -9999.9f, val2 = -9999.9f; - void set(float _val1, float _val2, bool _force) { - if (loc >= 0 && (_force || val1 != _val1 || val2 != _val2)) { - val1 = _val1; - val2 = _val2; - glUniform2f(loc, _val1, _val2); - } - } -}; - -struct fv3Uniform { - GLint loc = -1; - float val[3]; - void set(float * _pVal, bool _force) { - const size_t szData = sizeof(float)* 3; - if (loc >= 0 && (_force || memcmp(val, _pVal, szData) != 0)) { - memcpy(val, _pVal, szData); - glUniform3fv(loc, 1, _pVal); - } - } -}; - -struct fv4Uniform { - GLint loc = -1; - float val[4]; - void set(float * _pVal, bool _force) { - const size_t szData = sizeof(float)* 4; - if (loc >= 0 && (_force || memcmp(val, _pVal, szData) != 0)) { - memcpy(val, _pVal, szData); - glUniform4fv(loc, 1, _pVal); - } - } -}; - -struct iv2Uniform { - GLint loc = -1; - int val1 = -999, val2 = -999; - void set(int _val1, int _val2, bool _force) { - if (loc >= 0 && (_force || val1 != _val1 || val2 != _val2)) { - val1 = _val1; - val2 = _val2; - glUniform2i(loc, _val1, _val2); - } - } -}; - -struct i4Uniform { - GLint loc = -1; - int val0 = -999, val1 = -999, val2 = -999, val3 = -999; - void set(int _val0, int _val1, int _val2, int _val3, bool _force) { - if (loc < 0) - return; - if (_force || _val0 != val0 || _val1 != val1 || _val2 != val2 || _val3 != val3) { - val0 = _val0; - val1 = _val1; - val2 = _val2; - val3 = _val3; - glUniform4i(loc, val0, val1, val2, val3); - } - } -}; - - -/*---------------UniformGroup-------------*/ - -#define LocateUniform(A) \ - A.loc = glGetUniformLocation(_program, #A); - -class UNoiseTex : public UniformGroup +CombinerProgramUniformFactory::~CombinerProgramUniformFactory() { -public: - UNoiseTex(GLuint _program) { - LocateUniform(uTexNoise); - } - - void update(bool _force) override - { - uTexNoise.set(int(graphics::textureIndices::NoiseTex), _force); - } - -private: - iUniform uTexNoise; -}; - -class UDepthTex : public UniformGroup -{ -public: - UDepthTex(GLuint _program) { - LocateUniform(uDepthTex); - } - - void update(bool _force) override - { - uDepthTex.set(int(graphics::textureIndices::DepthTex), _force); - } - -private: - iUniform uDepthTex; -}; - -class UZLutTexture : public UniformGroup -{ -public: - UZLutTexture(GLuint _program) { - LocateUniform(uZlutImage); - } - - void update(bool _force) override - { - uZlutImage.set(int(graphics::textureIndices::ZLUTTex), _force); - } - -private: - iUniform uZlutImage; -}; - -class UTextures : public UniformGroup -{ -public: - UTextures(GLuint _program) { - LocateUniform(uTex0); - LocateUniform(uTex1); - } - - void update(bool _force) override - { - uTex0.set(0, _force); - uTex1.set(1, _force); - } - -private: - iUniform uTex0; - iUniform uTex1; -}; - -class UMSAATextures : public UniformGroup -{ -public: - UMSAATextures(GLuint _program) { - LocateUniform(uMSTex0); - LocateUniform(uMSTex1); - LocateUniform(uMSAASamples); - } - - void update(bool _force) override - { - uMSTex0.set(int(graphics::textureIndices::MSTex[0]), _force); - uMSTex1.set(int(graphics::textureIndices::MSTex[1]), _force); - uMSAASamples.set(config.video.multisampling, _force); - } - -private: - iUniform uMSTex0; - iUniform uMSTex1; - iUniform uMSAASamples; -}; - -class UScreenSpaceTriangleInfo : public UniformGroup -{ -public: - UScreenSpaceTriangleInfo(GLuint _program) { - LocateUniform(uScreenSpaceTriangle); - } - - void update(bool _force) override - { - uScreenSpaceTriangle.set( - (dwnd().getDrawer().getDrawingState() == DrawingState::ScreenSpaceTriangle) ? 1 : 0, _force); - } - -private: - iUniform uScreenSpaceTriangle; -}; - -class URasterInfo : public UniformGroup { -public: - URasterInfo(GLuint _program) { - LocateUniform(uVertexOffset); - LocateUniform(uTexCoordOffset[0]); - LocateUniform(uTexCoordOffset[1]); - LocateUniform(uUseTexCoordBounds); - LocateUniform(uTexCoordBounds0); - LocateUniform(uTexCoordBounds1); - } - - void update(bool _force) override { - const bool isNativeRes = config.frameBufferEmulation.nativeResFactor == 1 && config.video.multisampling == 0; - const bool isTexRect = dwnd().getDrawer().getDrawingState() == DrawingState::TexRect; - const bool useTexCoordBounds = isTexRect && !isNativeRes && config.graphics2D.enableTexCoordBounds; - /* At rasterization stage, the N64 places samples on the top left of the fragment while OpenGL */ - /* places them in the fragment center. As a result, a normal approach results in shifted texture */ - /* coordinates. In native resolution, this difference can be negated by shifting vertices by 0.5. */ - /* In higher resolutions, there are more samples than the game intends, so shifting is not very */ - /* effective. Still, an heuristic is applied to render texture rectangles as correctly as possible */ - /* in higher resolutions too. See issue #2324 for details. */ - const float vertexOffset = isNativeRes ? 0.5f : 0.0f; - float texCoordOffset[2][2] = { 0.0f, 0.0f }; - if (isTexRect && !isNativeRes) { - float scale[2] = { 0.0f, 0.0f }; - if (config.graphics2D.enableNativeResTexrects != 0 && gDP.otherMode.textureFilter != G_TF_POINT) { - scale[0] = scale[1] = 1.0f; - } else { - scale[0] = scale[1] = static_cast(config.frameBufferEmulation.nativeResFactor); - } - - for (int t = 0; t < 2; t++) { - const CachedTexture* _pTexture = textureCache().current[t]; - if (_pTexture != nullptr) { - if (config.frameBufferEmulation.nativeResFactor != 0) { - if (gDP.otherMode.textureFilter != G_TF_POINT && gDP.otherMode.cycleType != G_CYC_COPY) { - texCoordOffset[t][0] = -0.5f * gDP.lastTexRectInfo.dsdx; - texCoordOffset[t][1] = -0.5f * gDP.lastTexRectInfo.dtdy; - } else { - texCoordOffset[t][0] = (gDP.lastTexRectInfo.dsdx >= 0.0f ? -0.5f / scale[0] : -1.0f + 0.5f / scale[0]) * gDP.lastTexRectInfo.dsdx; - texCoordOffset[t][1] = (gDP.lastTexRectInfo.dtdy >= 0.0f ? -0.5f / scale[1] : -1.0f + 0.5f / scale[1]) * gDP.lastTexRectInfo.dtdy; - } - } else { - texCoordOffset[t][0] = (gDP.lastTexRectInfo.dsdx >= 0.0f ? 0.0f : -1.0f) * gDP.lastTexRectInfo.dsdx; - texCoordOffset[t][1] = (gDP.lastTexRectInfo.dtdy >= 0.0f ? 0.0f : -1.0f) * gDP.lastTexRectInfo.dtdy; - if (gDP.otherMode.textureFilter != G_TF_POINT && gDP.otherMode.cycleType != G_CYC_COPY) { - texCoordOffset[t][0] -= 0.5f; - texCoordOffset[t][1] -= 0.5f; - } - } - } - } - } - /* Hack for framebuffer textures. See #519 and #2112 */ - if ((config.generalEmulation.hacks & hack_fbTextureOffset) != 0) { - for (int t = 0; t < 2; t++) { - const CachedTexture* _pTexture = textureCache().current[t]; - if (_pTexture != nullptr) { - if (gDP.otherMode.textureFilter != G_TF_POINT && _pTexture->frameBufferTexture != CachedTexture::fbNone) { - texCoordOffset[t][0] -= 1.0f; - texCoordOffset[t][1] -= 1.0f; - } - } - } - } - float tcbounds[2][4] = {}; - if (useTexCoordBounds) { - f32 uls, lrs, ult, lrt, S, T; - for (int t = 0; t < 2; t++) { - const CachedTexture * _pTexture = textureCache().current[t]; - if (_pTexture != nullptr) { - S = _FIXED2FLOAT(gDP.lastTexRectInfo.s, 5); - T = _FIXED2FLOAT(gDP.lastTexRectInfo.t, 5); - uls = S + (ceilf(gDP.lastTexRectInfo.ulx) - gDP.lastTexRectInfo.ulx) * gDP.lastTexRectInfo.dsdx; - lrs = S + (ceilf(gDP.lastTexRectInfo.lrx) - gDP.lastTexRectInfo.ulx - 1.0f) * gDP.lastTexRectInfo.dsdx; - ult = T + (ceilf(gDP.lastTexRectInfo.uly) - gDP.lastTexRectInfo.uly) * gDP.lastTexRectInfo.dtdy; - lrt = T + (ceilf(gDP.lastTexRectInfo.lry) - gDP.lastTexRectInfo.uly - 1.0f) * gDP.lastTexRectInfo.dtdy; - tcbounds[t][0] = fmin(uls, lrs); - tcbounds[t][1] = fmin(ult, lrt); - tcbounds[t][2] = fmax(uls, lrs); - tcbounds[t][3] = fmax(ult, lrt); - } - } - } - - uVertexOffset.set(vertexOffset, vertexOffset, _force); - uTexCoordOffset[0].set(texCoordOffset[0][0], texCoordOffset[0][1], _force); - uTexCoordOffset[1].set(texCoordOffset[1][0], texCoordOffset[1][1], _force); - uUseTexCoordBounds.set(useTexCoordBounds ? 1 : 0, _force); - uTexCoordBounds0.set(tcbounds[0], _force); - uTexCoordBounds1.set(tcbounds[1], _force); - } - -private: - fv2Uniform uVertexOffset; - fv2Uniform uTexCoordOffset[2]; - iUniform uUseTexCoordBounds; - fv4Uniform uTexCoordBounds0; - fv4Uniform uTexCoordBounds1; -}; - -class UFrameBufferInfo : public UniformGroup -{ -public: - UFrameBufferInfo(GLuint _program) { - LocateUniform(uFbMonochrome); - LocateUniform(uFbFixedAlpha); - LocateUniform(uMSTexEnabled); - } - - void update(bool _force) override - { - int nFbMonochromeMode0 = 0, nFbMonochromeMode1 = 0; - int nFbFixedAlpha0 = 0, nFbFixedAlpha1 = 0; - int nMSTex0Enabled = 0, nMSTex1Enabled = 0; - TextureCache & cache = textureCache(); - if (cache.current[0] != nullptr && cache.current[0]->frameBufferTexture != CachedTexture::fbNone) { - if (cache.current[0]->size == G_IM_SIZ_8b) { - nFbMonochromeMode0 = 1; - if (gDP.otherMode.imageRead == 0) - nFbFixedAlpha0 = 1; - } else if (gSP.textureTile[0]->size == G_IM_SIZ_16b && gSP.textureTile[0]->format == G_IM_FMT_IA) { - nFbMonochromeMode0 = 2; - } else if ((config.generalEmulation.hacks & hack_ZeldaMonochrome) != 0 && - cache.current[0]->size == G_IM_SIZ_16b && - gSP.textureTile[0]->size == G_IM_SIZ_8b && - gSP.textureTile[0]->format == G_IM_FMT_CI) { - // Zelda monochrome effect - nFbMonochromeMode0 = 3; - nFbMonochromeMode1 = 3; - } - - nMSTex0Enabled = cache.current[0]->frameBufferTexture == CachedTexture::fbMultiSample ? 1 : 0; - } - if (cache.current[1] != nullptr && cache.current[1]->frameBufferTexture != CachedTexture::fbNone) { - if (cache.current[1]->size == G_IM_SIZ_8b) { - nFbMonochromeMode1 = 1; - if (gDP.otherMode.imageRead == 0) - nFbFixedAlpha1 = 1; - } - else if (gSP.textureTile[1]->size == G_IM_SIZ_16b && gSP.textureTile[1]->format == G_IM_FMT_IA) - nFbMonochromeMode1 = 2; - nMSTex1Enabled = cache.current[1]->frameBufferTexture == CachedTexture::fbMultiSample ? 1 : 0; - } - uFbMonochrome.set(nFbMonochromeMode0, nFbMonochromeMode1, _force); - uFbFixedAlpha.set(nFbFixedAlpha0, nFbFixedAlpha1, _force); - uMSTexEnabled.set(nMSTex0Enabled, nMSTex1Enabled, _force); - gDP.changed &= ~CHANGED_FB_TEXTURE; - } - -private: - iv2Uniform uFbMonochrome; - iv2Uniform uFbFixedAlpha; - iv2Uniform uMSTexEnabled; -}; - - -class UFog : public UniformGroup -{ -public: - UFog(GLuint _program) { - LocateUniform(uFogUsage); - LocateUniform(uFogScale); - } - - void update(bool _force) override - { - if (RSP.LLE) { - uFogUsage.set(0, _force); - return; - } - - int nFogUsage = ((gSP.geometryMode & G_FOG) != 0) ? 1 : 0; - if (GBI.getMicrocodeType() == F3DAM) { - const s16 fogMode = ((gSP.geometryMode >> 13) & 9) + 0xFFF8; - if (fogMode == 0) - nFogUsage = 1; - else if (fogMode > 0) - nFogUsage = 2; - } - uFogUsage.set(nFogUsage, _force); - uFogScale.set(gSP.fog.multiplierf, gSP.fog.offsetf, _force); - } - -private: - iUniform uFogUsage; - fv2Uniform uFogScale; -}; - -class UBlendMode1Cycle : public UniformGroup -{ -public: - UBlendMode1Cycle(GLuint _program) { - LocateUniform(uBlendMux1); - LocateUniform(uForceBlendCycle1); - } - - void update(bool _force) override - { - uBlendMux1.set(gDP.otherMode.c1_m1a, - gDP.otherMode.c1_m1b, - gDP.otherMode.c1_m2a, - gDP.otherMode.c1_m2b, - _force); - - const int forceBlend1 = (int)gDP.otherMode.forceBlender; - uForceBlendCycle1.set(forceBlend1, _force); - } - -private: - i4Uniform uBlendMux1; - iUniform uForceBlendCycle1; -}; - -class UBlendMode2Cycle : public UniformGroup -{ -public: - UBlendMode2Cycle(GLuint _program) { - LocateUniform(uBlendMux1); - LocateUniform(uBlendMux2); - LocateUniform(uForceBlendCycle1); - LocateUniform(uForceBlendCycle2); - } - - void update(bool _force) override - { - uBlendMux1.set(gDP.otherMode.c1_m1a, - gDP.otherMode.c1_m1b, - gDP.otherMode.c1_m2a, - gDP.otherMode.c1_m2b, - _force); - - uBlendMux2.set(gDP.otherMode.c2_m1a, - gDP.otherMode.c2_m1b, - gDP.otherMode.c2_m2a, - gDP.otherMode.c2_m2b, - _force); - - const int forceBlend1 = 1; - uForceBlendCycle1.set(forceBlend1, _force); - const int forceBlend2 = gDP.otherMode.forceBlender; - uForceBlendCycle2.set(forceBlend2, _force); - - if (!(graphics::Context::DualSourceBlending || graphics::Context::FramebufferFetchColor) || dwnd().getDrawer().isTexrectDrawerMode()) { - // Modes, which shader blender can't emulate - const u32 mode = _SHIFTR(gDP.otherMode.l, 16, 16); - switch (mode) { - case 0x0040: - // Mia Hamm Soccer - // clr_in * a_in + clr_mem * (1-a) - // clr_in * a_in + clr_in * (1-a) - case 0x0050: - // A Bug's Life - // clr_in * a_in + clr_mem * (1-a) - // clr_in * a_in + clr_mem * (1-a) - uForceBlendCycle1.set(0, _force); - uForceBlendCycle2.set(0, _force); - break; - case 0x0150: - // Tony Hawk - // clr_in * a_in + clr_mem * (1-a) - // clr_in * a_fog + clr_mem * (1-a_fog) - if ((config.generalEmulation.hacks & hack_TonyHawk) != 0) { - uForceBlendCycle1.set(0, _force); - uForceBlendCycle2.set(0, _force); - } - break; - } - } - - } - -private: - i4Uniform uBlendMux1; - i4Uniform uBlendMux2; - iUniform uForceBlendCycle1; - iUniform uForceBlendCycle2; -}; - -class UBlendCvg : public UniformGroup -{ -public: - UBlendCvg(GLuint _program) { - LocateUniform(uCvgDest); - LocateUniform(uBlendAlphaMode); - } - - void update(bool _force) override - { - uCvgDest.set(gDP.otherMode.cvgDest, _force); - if (dwnd().getDrawer().isTexrectDrawerMode()) - uBlendAlphaMode.set(2, _force); // No alpha blend in texrect drawing mode - else - uBlendAlphaMode.set(gDP.otherMode.forceBlender, _force); - } -private: - iUniform uCvgDest; - iUniform uBlendAlphaMode; -}; - -class UDitherMode : public UniformGroup -{ -public: - UDitherMode(GLuint _program, bool _usesNoise) - : m_usesNoise(_usesNoise) - { - LocateUniform(uAlphaCompareMode); - LocateUniform(uAlphaDitherMode); - LocateUniform(uColorDitherMode); - } - - void update(bool _force) override - { - if (gDP.otherMode.cycleType < G_CYC_COPY) { - uAlphaCompareMode.set(gDP.otherMode.alphaCompare, _force); - uAlphaDitherMode.set(gDP.otherMode.alphaDither, _force); - uColorDitherMode.set(gDP.otherMode.colorDither, _force); - } - else { - uAlphaCompareMode.set(0, _force); - uAlphaDitherMode.set(0, _force); - uColorDitherMode.set(0, _force); - } - - bool updateNoiseTex = m_usesNoise; - updateNoiseTex |= (gDP.otherMode.cycleType < G_CYC_COPY) && (gDP.otherMode.colorDither == G_CD_NOISE || gDP.otherMode.alphaDither == G_AD_NOISE || gDP.otherMode.alphaCompare == G_AC_DITHER); - if (updateNoiseTex) - g_noiseTexture.update(); - } - -private: - iUniform uAlphaCompareMode; - iUniform uAlphaDitherMode; - iUniform uColorDitherMode; - bool m_usesNoise; -}; - -class UScreenScale : public UniformGroup -{ -public: - UScreenScale(GLuint _program) { - LocateUniform(uScreenScale); - } - - void update(bool _force) override - { - if (dwnd().getDrawer().isTexrectDrawerMode()) { - uScreenScale.set(1.0f, 1.0f, _force); - return; - } - - FrameBuffer * pBuffer = frameBufferList().getCurrent(); - if (pBuffer == nullptr) - uScreenScale.set(dwnd().getScaleX(), dwnd().getScaleY(), _force); - else - uScreenScale.set(pBuffer->m_scale, pBuffer->m_scale, _force); - } - -private: - fv2Uniform uScreenScale; -}; - -class UMipmap : public UniformGroup -{ -public: - UMipmap(GLuint _program) { - LocateUniform(uMinLod); - LocateUniform(uMaxTile); - LocateUniform(uEnableLod); - LocateUniform(uTextureDetail); - } - - void update(bool _force) override - { - uMinLod.set(gDP.primColor.m, _force); - const CachedTexture * _pTexture = textureCache().current[1]; - if (_pTexture == nullptr) - uMaxTile.set(gSP.texture.level, _force); - else - uMaxTile.set(_pTexture->max_level > 0 ? gSP.texture.level : std::min(gSP.texture.level, 1u), _force); - const int uCalcLOD = (gDP.otherMode.textureLOD == G_TL_LOD) ? 1 : 0; - uEnableLod.set(uCalcLOD, _force); - uTextureDetail.set(gDP.otherMode.textureDetail, _force); - } - -private: - fUniform uMinLod; - iUniform uMaxTile; - iUniform uEnableLod; - iUniform uTextureDetail; -}; - -class UTexturePersp : public UniformGroup -{ -public: - UTexturePersp(GLuint _program) { - LocateUniform(uTexturePersp); - } - - void update(bool _force) override - { - const u32 texturePersp = (RSP.LLE || GBI.isTexturePersp()) ? gDP.otherMode.texturePersp : 1U; - uTexturePersp.set(texturePersp, _force); - } - -private: - iUniform uTexturePersp; -}; - -class UTextureFetchMode : public UniformGroup -{ -public: - UTextureFetchMode(GLuint _program) { - LocateUniform(uTextureFilterMode); - LocateUniform(uTextureFormat); - LocateUniform(uTextureConvert); - LocateUniform(uConvertParams); - } - - void update(bool _force) override - { - int textureFilter = gDP.otherMode.textureFilter; - uTextureFilterMode.set(textureFilter, _force); - uTextureFormat.set(gSP.textureTile[0]->format, gSP.textureTile[1]->format, _force); - uTextureConvert.set(gDP.otherMode.convert_one, _force); - if (gDP.otherMode.bi_lerp0 == 0 || gDP.otherMode.bi_lerp1 == 0) - uConvertParams.set(gDP.convert.k0, gDP.convert.k1, gDP.convert.k2, gDP.convert.k3, _force); - } - -private: - iUniform uTextureFilterMode; - iv2Uniform uTextureFormat; - iUniform uTextureConvert; - i4Uniform uConvertParams; -}; - -class UAlphaTestInfo : public UniformGroup -{ -public: - UAlphaTestInfo(GLuint _program) { - LocateUniform(uEnableAlphaTest); - LocateUniform(uAlphaCvgSel); - LocateUniform(uCvgXAlpha); - LocateUniform(uAlphaTestValue); - } - - void update(bool _force) override - { - if (gDP.otherMode.cycleType == G_CYC_FILL) { - uEnableAlphaTest.set(0, _force); - uAlphaCvgSel.set(0, _force); - - } else if (gDP.otherMode.cycleType == G_CYC_COPY) { - uAlphaCvgSel.set(0, _force); - if (gDP.otherMode.alphaCompare & G_AC_THRESHOLD) { - uEnableAlphaTest.set(1, _force); - uAlphaTestValue.set(0.5f, _force); - } else { - uEnableAlphaTest.set(0, _force); - } - } else if ((gDP.otherMode.alphaCompare & G_AC_THRESHOLD) != 0) { - uEnableAlphaTest.set(1, _force); - uAlphaTestValue.set(gDP.blendColor.a, _force); - uAlphaCvgSel.set(gDP.otherMode.alphaCvgSel, _force); - } else { - uEnableAlphaTest.set(0, _force); - uAlphaCvgSel.set(gDP.otherMode.alphaCvgSel, _force); - } - - uCvgXAlpha.set(gDP.otherMode.cvgXAlpha, _force); - } - -private: - iUniform uEnableAlphaTest; - iUniform uAlphaCvgSel; - iUniform uCvgXAlpha; - fUniform uAlphaTestValue; -}; - -class UViewportInfo : public UniformGroup -{ -public: - UViewportInfo(GLuint _program) { - LocateUniform(uVTrans); - LocateUniform(uVScale); - LocateUniform(uAdjustTrans); - LocateUniform(uAdjustScale); - } - - void update(bool _force) override - { - const bool isOrthographicProjection = gSP.matrix.projection[3][2] == -1.f; - float adjustTrans[2] = { 0.0f, 0.0f }; - float adjustScale[2] = { 1.0f, 1.0f }; - if (dwnd().isAdjustScreen() && (gDP.colorImage.width > VI.width * 98 / 100)) { - if (isOrthographicProjection) { - adjustScale[1] = 1.0f / dwnd().getAdjustScale(); - adjustTrans[1] = static_cast(gDP.colorImage.width) * 3.0f / 4.0f * (1.0f - adjustScale[1]) / 2.0f; - } else { - adjustScale[0] = dwnd().getAdjustScale(); - adjustTrans[0] = static_cast(gDP.colorImage.width) * (1.0f - adjustScale[0]) / 2.0f; - } - } - uVTrans.set(gSP.viewport.vtrans[0], gSP.viewport.vtrans[1], _force); - uVScale.set(gSP.viewport.vscale[0], -gSP.viewport.vscale[1], _force); - uAdjustTrans.set(adjustTrans[0], adjustTrans[1], _force); - uAdjustScale.set(adjustScale[0], adjustScale[1], _force); - } - -private: - fv2Uniform uVTrans; - fv2Uniform uVScale; - fv2Uniform uAdjustTrans; - fv2Uniform uAdjustScale; -}; - -class UDepthScale : public UniformGroup -{ -public: - UDepthScale(GLuint _program) { - LocateUniform(uDepthScale); - } - - void update(bool _force) override - { - if (RSP.LLE) - uDepthScale.set(0.5f, 0.5f, _force); - else - uDepthScale.set(gSP.viewport.vscale[2], gSP.viewport.vtrans[2], _force); - } - -private: - fv2Uniform uDepthScale; -}; - -class UDepthInfo : public UniformGroup -{ -public: - UDepthInfo(GLuint _program) { - LocateUniform(uEnableDepth); - LocateUniform(uEnableDepthCompare); - LocateUniform(uEnableDepthUpdate); - LocateUniform(uDepthMode); - LocateUniform(uDepthSource); - LocateUniform(uPrimDepth); - LocateUniform(uDeltaZ); - } - - void update(bool _force) override - { - FrameBuffer * pBuffer = frameBufferList().getCurrent(); - if (pBuffer == nullptr || pBuffer->m_pDepthBuffer == nullptr) - return; - - const bool nDepthEnabled = ((gSP.geometryMode & G_ZBUFFER) || gDP.otherMode.depthSource == G_ZS_PRIM) && - gDP.otherMode.cycleType <= G_CYC_2CYCLE; - uEnableDepth.set(nDepthEnabled ? 1 : 0, _force); - if (nDepthEnabled) { - uEnableDepthCompare.set(gDP.otherMode.depthCompare, _force); - uEnableDepthUpdate.set(gDP.otherMode.depthUpdate, _force); - } else { - uEnableDepthCompare.set(0, _force); - uEnableDepthUpdate.set(0, _force); - } - uDepthMode.set(gDP.otherMode.depthMode, _force); - uDepthSource.set(gDP.otherMode.depthSource, _force); - if (gDP.otherMode.depthSource == G_ZS_PRIM) { - uDeltaZ.set(gDP.primDepth.deltaZ, _force); - uPrimDepth.set(gDP.primDepth.z, _force); - } - } - -private: - iUniform uEnableDepth; - iUniform uEnableDepthCompare; - iUniform uEnableDepthUpdate; - iUniform uDepthMode; - iUniform uDepthSource; - fUniform uPrimDepth; - fUniform uDeltaZ; -}; - -class UDepthSource : public UniformGroup -{ -public: - UDepthSource(GLuint _program) { - LocateUniform(uDepthSource); - LocateUniform(uPrimDepth); - } - - void update(bool _force) override - { - uDepthSource.set(gDP.otherMode.depthSource, _force); - if (gDP.otherMode.depthSource == G_ZS_PRIM) - uPrimDepth.set(gDP.primDepth.z, _force); - } - -private: - iUniform uDepthSource; - fUniform uPrimDepth; -}; - -class URenderTarget : public UniformGroup -{ -public: - URenderTarget(GLuint _program) { - LocateUniform(uRenderTarget); - } - - void update(bool _force) override - { - int renderTarget = 0; - if (isCurrentColorImageDepthImage()) { - renderTarget = isDepthCompareEnabled() ? 2 : 1; - } - uRenderTarget.set(renderTarget, _force); - } - -private: - iUniform uRenderTarget; -}; - -class UClampMode : public UniformGroup -{ -public: - UClampMode(GLuint _program) { - LocateUniform(uClampMode); - } - - void update(bool _force) override - { - int clampMode = -1; - switch (gfxContext.getClampMode()) - { - case graphics::ClampMode::ClippingEnabled: - clampMode = 0; - break; - case graphics::ClampMode::NoNearPlaneClipping: - clampMode = 1; - break; - case graphics::ClampMode::NoClipping: - clampMode = 2; - break; - } - uClampMode.set(clampMode, _force); - } - -private: - iUniform uClampMode; -}; - -class UPolygonOffset : public UniformGroup -{ -public: - UPolygonOffset(GLuint _program) { - LocateUniform(uPolygonOffset); - } - - void update(bool _force) override - { - f32 offset = gfxContext.isEnabled(graphics::enable::POLYGON_OFFSET_FILL) ? 0.003f : 0.0f; - uPolygonOffset.set(offset, _force); - } - -private: - fUniform uPolygonOffset; -}; - -class UScreenCoordsScale : public UniformGroup -{ -public: - UScreenCoordsScale(GLuint _program) { - LocateUniform(uScreenCoordsScale); - } - - void update(bool _force) override - { - f32 scaleX, scaleY; - calcCoordsScales(frameBufferList().getCurrent(), scaleX, scaleY); - uScreenCoordsScale.set(2.0f*scaleX, -2.0f*scaleY, _force); - } - -private: - fv2Uniform uScreenCoordsScale; -}; - -class UColors : public UniformGroup -{ -public: - UColors(GLuint _program) { - LocateUniform(uFogColor); - LocateUniform(uCenterColor); - LocateUniform(uScaleColor); - LocateUniform(uBlendColor); - LocateUniform(uEnvColor); - LocateUniform(uPrimColor); - LocateUniform(uPrimLod); - LocateUniform(uK4); - LocateUniform(uK5); - } - - void update(bool _force) override - { - uFogColor.set(&gDP.fogColor.r, _force); - uCenterColor.set(&gDP.key.center.r, _force); - uScaleColor.set(&gDP.key.scale.r, _force); - uBlendColor.set(&gDP.blendColor.r, _force); - uEnvColor.set(&gDP.envColor.r, _force); - uPrimColor.set(&gDP.primColor.r, _force); - uPrimLod.set(gDP.primColor.l, _force); - uK4.set(_FIXED2FLOATCOLOR(gDP.convert.k4, 8 ), _force); - uK5.set(_FIXED2FLOATCOLOR(gDP.convert.k5, 8 ), _force); - } - -private: - fv4Uniform uFogColor; - fv4Uniform uCenterColor; - fv4Uniform uScaleColor; - fv4Uniform uBlendColor; - fv4Uniform uEnvColor; - fv4Uniform uPrimColor; - fUniform uPrimLod; - fUniform uK4; - fUniform uK5; -}; - -class URectColor : public UniformGroup -{ -public: - URectColor(GLuint _program) { - LocateUniform(uRectColor); - } - - void update(bool _force) override - { - uRectColor.set(&gDP.rectColor.r, _force); - } - -private: - fv4Uniform uRectColor; -}; - -class UTextureSize : public UniformGroup -{ -public: - UTextureSize(GLuint _program, bool _useT0, bool _useT1) - : m_useT0(_useT0) - , m_useT1(_useT1) - { - LocateUniform(uTextureSize[0]); - LocateUniform(uTextureSize[1]); - } - - void update(bool _force) override - { - TextureCache & cache = textureCache(); - if (m_useT0 && cache.current[0] != nullptr) - uTextureSize[0].set(static_cast(cache.current[0]->width), - static_cast(cache.current[0]->height), _force); - if (m_useT1 && cache.current[1] != nullptr) { - CachedTexture * pTexture = cache.current[1]; - if (pTexture->max_level == 0) - uTextureSize[1].set(static_cast(pTexture->width), - static_cast(pTexture->height), _force); - else - uTextureSize[1].set(static_cast(pTexture->mipmapAtlasWidth), - static_cast(pTexture->mipmapAtlasHeight), _force); - } - } - -private: - fv2Uniform uTextureSize[2]; - bool m_useT0; - bool m_useT1; -}; - -class UTextureParams : public UniformGroup -{ -public: - UTextureParams(GLuint _program, bool _useT0, bool _useT1) - { - m_useTile[0] = _useT0; - m_useTile[1] = _useT1; - LocateUniform(uTexScale); - LocateUniform(uCacheFrameBuffer); - } - - void update(bool _force) override - { - int nFB[2] = { 0, 0 }; - TextureCache & cache = textureCache(); - for (u32 t = 0; t < 2; ++t) { - if (!m_useTile[t]) - continue; - CachedTexture *_pTexture = cache.current[t]; - if (_pTexture != nullptr) { - nFB[t] = _pTexture->frameBufferTexture; - } - } - - uCacheFrameBuffer.set(nFB[0], nFB[1], _force); - uTexScale.set(gSP.texture.scales, gSP.texture.scalet, _force); - } - -private: - bool m_useTile[2]; - fv2Uniform uTexScale; - iv2Uniform uCacheFrameBuffer; -}; - -class UTextureEngine : public UniformGroup -{ -public: - UTextureEngine(GLuint _program, bool _useT0, bool _useT1) - { - m_useTile[0] = _useT0; - m_useTile[1] = _useT1; - LocateUniform(uTexWrap[0]); - LocateUniform(uTexWrap[1]); - LocateUniform(uTexClamp[0]); - LocateUniform(uTexClamp[1]); - LocateUniform(uTexWrapEn[0]); - LocateUniform(uTexWrapEn[1]); - LocateUniform(uTexClampEn[0]); - LocateUniform(uTexClampEn[1]); - LocateUniform(uTexMirrorEn[0]); - LocateUniform(uTexMirrorEn[1]); - LocateUniform(uTexSize[0]); - LocateUniform(uTexSize[1]); - LocateUniform(uShiftScale[0]); - LocateUniform(uShiftScale[1]); - LocateUniform(uTexOffset[0]); - LocateUniform(uTexOffset[1]); - LocateUniform(uHDRatio[0]); - LocateUniform(uHDRatio[1]); - LocateUniform(uCacheOffset[0]); - LocateUniform(uCacheOffset[1]); - LocateUniform(uBilinearOffset); - } - - void update(bool _force) override - { - std::array aTexWrap[2] = { { 1024.0f, 1024.0f }, { 1024.0f, 1024.0f } }; - std::array aTexClamp[2] = { { 1024.0f, 1024.0f }, { 1024.0f, 1024.0f } }; - std::array aTexWrapEn[2] = { { 0.0f, 0.0f }, { 0.0f, 0.0f } }; - std::array aTexClampEn[2] = { { 0.0f, 0.0f }, { 0.0f, 0.0f } }; - std::array aTexMirrorEn[2] = { { 0.0f, 0.0f }, { 0.0f,0.0f }}; - std::array aTexSize[2] = { { 1024.0f, 1024.0f }, { 1024.0f, 1024.0f } }; - - std::array aShiftScale[2] = { { 1.0f, 1.0f }, { 1.0f,1.0f } }; - std::array aTexOffset[2] = { { 0.0f, 0.0f }, { 0.0f, 0.0f } }; - - std::array aHDRatio[2] = { { 1.0f, 1.0f }, { 1.0f, 1.0f } }; - std::array aCacheOffset[2] = { { 0.0f, 0.0f }, { 0.0f, 0.0f } }; - - const float bilinearOffset = gDP.otherMode.textureFilter != G_TF_POINT && gDP.otherMode.cycleType != G_CYC_COPY ? 0.5f : 0.0f; - uBilinearOffset.set(bilinearOffset, bilinearOffset, _force); - - TextureCache & cache = textureCache(); - for (u32 t = 0; t < 2; ++t) { - if (!m_useTile[t]) - continue; - - const gDPTile * pTile = gSP.textureTile[t]; - CachedTexture * pTexture = cache.current[t]; - if (pTile == nullptr || pTexture == nullptr) - continue; - - aTexSize[t][0] = pTexture->width * pTexture->hdRatioS; - aTexSize[t][1] = pTexture->height * pTexture->hdRatioT; - - aShiftScale[t][0] = pTile->shifts > 10 ? static_cast(1 << (16 - pTile->shifts)) : 1.0f / static_cast(1 << pTile->shifts); - aShiftScale[t][1] = pTile->shiftt > 10 ? static_cast(1 << (16 - pTile->shiftt)) : 1.0f / static_cast(1 << pTile->shiftt); - - if (pTile->textureMode != TEXTUREMODE_BGIMAGE && pTile->textureMode != TEXTUREMODE_FRAMEBUFFER_BG) { - aTexOffset[t][0] = pTile->fuls; - aTexOffset[t][1] = pTile->fult; - } - - aHDRatio[t][0] = pTexture->hdRatioS; - aHDRatio[t][1] = pTexture->hdRatioT; - - aCacheOffset[t][0] = pTexture->offsetS * pTexture->hdRatioS; - aCacheOffset[t][1] = pTexture->offsetT * pTexture->hdRatioT; - - /* Not sure if special treatment of framebuffer textures is correct */ - if (pTexture->frameBufferTexture != CachedTexture::fbNone) - { - aTexClamp[t][0] = f32(pTexture->width) * pTexture->hdRatioS - 1.0f; - aTexClamp[t][1] = f32(pTexture->height) * pTexture->hdRatioT - 1.0f; - aTexWrapEn[t][0] = 0.0; - aTexWrapEn[t][1] = 0.0; - aTexClampEn[t][0] = 1.0; - aTexClampEn[t][1] = 1.0; - aTexMirrorEn[t][0] = 0.0; - aTexMirrorEn[t][1] = 0.0; - } else if (pTile->textureMode != TEXTUREMODE_NORMAL || g_debugger.isDebugMode()) { - aTexWrapEn[t][0] = 0.0; - aTexWrapEn[t][1] = 0.0; - aTexClampEn[t][0] = 0.0; - aTexClampEn[t][1] = 0.0; - aTexMirrorEn[t][0] = 0.0; - aTexMirrorEn[t][1] = 0.0; - } else { - aTexWrap[t][0] = f32(1 << pTile->masks) * pTexture->hdRatioS; - aTexWrap[t][1] = f32(1 << pTile->maskt) * pTexture->hdRatioT; - aTexClamp[t][0] = f32(pTile->lrs - pTile->uls + 1) * pTexture->hdRatioS - 1.0f; - aTexClamp[t][1] = f32(pTile->lrt - pTile->ult + 1) * pTexture->hdRatioT - 1.0f; - aTexWrapEn[t][0] = f32(pTile->masks == 0 ? 0 : 1); - aTexWrapEn[t][1] = f32(pTile->maskt == 0 ? 0 : 1); - aTexClampEn[t][0] = f32(gDP.otherMode.cycleType == G_CYC_COPY ? 0 : (pTile->masks == 0 ? 1 : pTile->clamps)); - aTexClampEn[t][1] = f32(gDP.otherMode.cycleType == G_CYC_COPY ? 0 : (pTile->maskt == 0 ? 1 : pTile->clampt)); - aTexMirrorEn[t][0] = f32(pTile->masks == 0 ? 0 : pTile->mirrors); - aTexMirrorEn[t][1] = f32(pTile->maskt == 0 ? 0 : pTile->mirrort); - } - - uTexWrap[t].set(aTexWrap[t][0], aTexWrap[t][1], _force); - uTexClamp[t].set(aTexClamp[t][0], aTexClamp[t][1], _force); - uTexWrapEn[t].set(aTexWrapEn[t][0], aTexWrapEn[t][1], _force); - uTexWrapEn[t].set(aTexWrapEn[t][0], aTexWrapEn[t][1], _force); - uTexClampEn[t].set(aTexClampEn[t][0], aTexClampEn[t][1], _force); - uTexMirrorEn[t].set(aTexMirrorEn[t][0], aTexMirrorEn[t][1], _force); - uTexSize[t].set(aTexSize[t][0], aTexSize[t][1], _force); - uShiftScale[t].set(aShiftScale[t][0], aShiftScale[t][1], _force); - uTexOffset[t].set(aTexOffset[t][0], aTexOffset[t][1], _force); - uHDRatio[t].set(aHDRatio[t][0], aHDRatio[t][1], _force); - uCacheOffset[t].set(aCacheOffset[t][0], aCacheOffset[t][1], _force); - } - - } - -private: - bool m_useTile[2]; - fv2Uniform uTexWrap[2]; - fv2Uniform uTexClamp[2]; - fv2Uniform uTexWrapEn[2]; - fv2Uniform uTexClampEn[2]; - fv2Uniform uTexMirrorEn[2]; - fv2Uniform uTexSize[2]; - fv2Uniform uShiftScale[2]; - fv2Uniform uTexOffset[2]; - fv2Uniform uHDRatio[2]; - fv2Uniform uCacheOffset[2]; - fv2Uniform uBilinearOffset; -}; - -class ULights : public UniformGroup -{ -public: - ULights(GLuint _program) - { - char buf[32]; - for (s32 i = 0; i < 8; ++i) { - sprintf(buf, "uLightDirection[%d]", i); - uLightDirection[i].loc = glGetUniformLocation(_program, buf); - sprintf(buf, "uLightColor[%d]", i); - uLightColor[i].loc = glGetUniformLocation(_program, buf); - } - } - - void update(bool _force) override - { - for (u32 i = 0; i <= gSP.numLights; ++i) { - uLightDirection[i].set(gSP.lights.xyz[i], _force); - uLightColor[i].set(gSP.lights.rgb[i], _force); - } - } - -private: - fv3Uniform uLightDirection[8]; - fv3Uniform uLightColor[8]; -}; - - -/*---------------CombinerProgramUniformFactory-------------*/ +} void CombinerProgramUniformFactory::buildUniforms(GLuint _program, - const CombinerInputs & _inputs, - const CombinerKey & _key, - UniformGroups & _uniforms) -{ - _uniforms.emplace_back(new UNoiseTex(_program)); - _uniforms.emplace_back(new UScreenSpaceTriangleInfo(_program)); - _uniforms.emplace_back(new URasterInfo(_program)); - _uniforms.emplace_back(new UViewportInfo(_program)); + const CombinerInputs &_inputs, + const CombinerKey &_key, + UniformGroups &_uniforms) { + + _addNoiseTex(_program, _uniforms); + _addScreenSpaceTriangleInfo(_program, _uniforms); + _addRasterInfo(_program, _uniforms); + _addViewportInfo(_program, _uniforms); if (!m_glInfo.isGLES2) { - _uniforms.emplace_back(new UDepthTex(_program)); - _uniforms.emplace_back(new UDepthScale(_program)); + _addDepthTex(_program, _uniforms); + _addDepthScale(_program, _uniforms); } if (_inputs.usesTexture()) { - _uniforms.emplace_back(new UTextures(_program)); + _addTextures(_program, _uniforms); if (config.video.multisampling != 0) - _uniforms.emplace_back(new UMSAATextures(_program)); + _addMSAATextures(_program, _uniforms); - _uniforms.emplace_back(new UFrameBufferInfo(_program)); + _addFrameBufferInfo(_program, _uniforms); if (_inputs.usesLOD()) { - _uniforms.emplace_back(new UMipmap(_program)); + _addMipmap(_program, _uniforms); + if (config.generalEmulation.enableLOD != 0) + _addMipmap2(_program, _uniforms); } else if (_key.getCycleType() < G_CYC_COPY) { - _uniforms.emplace_back(new UTextureFetchMode(_program)); + _addTextureFetchMode(_program, _uniforms); } - _uniforms.emplace_back(new UTexturePersp(_program)); + _addTexturePersp(_program, _uniforms); if (m_glInfo.isGLES2) - _uniforms.emplace_back(new UTextureSize(_program, _inputs.usesTile(0), _inputs.usesTile(1))); + _addTextureSize(_program, _uniforms, _inputs.usesTile(0), _inputs.usesTile(1)); if (!_key.isRectKey()) - _uniforms.emplace_back(new UTextureParams(_program, _inputs.usesTile(0), _inputs.usesTile(1))); + _addTextureParams(_program, _uniforms, _inputs.usesTile(0), _inputs.usesTile(1)); - _uniforms.emplace_back(new UTextureEngine(_program, _inputs.usesTile(0), _inputs.usesTile(1))); + _addClampWrapMirrorEngine(_program, _uniforms, _inputs.usesTile(0), _inputs.usesTile(1)); } - _uniforms.emplace_back(new UFog(_program)); + _addFog(_program, _uniforms); if (config.generalEmulation.enableLegacyBlending == 0) { switch (_key.getCycleType()) { - case G_CYC_1CYCLE: - _uniforms.emplace_back(new UBlendMode1Cycle(_program)); - break; - case G_CYC_2CYCLE: - _uniforms.emplace_back(new UBlendMode2Cycle(_program)); - break; + case G_CYC_1CYCLE: + _addBlendMode1Cycle(_program, _uniforms); + break; + case G_CYC_2CYCLE: + _addBlendMode2Cycle(_program, _uniforms); + break; } } - _uniforms.emplace_back(new UBlendCvg(_program)); + _addBlendCvg(_program, _uniforms); - _uniforms.emplace_back(new UDitherMode(_program, _inputs.usesNoise())); + _addDitherMode(_program, _uniforms, _inputs.usesNoise()); - _uniforms.emplace_back(new UScreenScale(_program)); + _addScreenScale(_program, _uniforms); - _uniforms.emplace_back(new UAlphaTestInfo(_program)); + _addAlphaTestInfo(_program, _uniforms); if ((config.generalEmulation.hacks & hack_RE2) != 0 && config.generalEmulation.enableFragmentDepthWrite != 0) - _uniforms.emplace_back(new UZLutTexture(_program)); + _addZLutTexture(_program, _uniforms); if (config.frameBufferEmulation.N64DepthCompare != Config::dcDisable) - _uniforms.emplace_back(new UDepthInfo(_program)); + _addDepthInfo(_program, _uniforms); else - _uniforms.emplace_back(new UDepthSource(_program)); + _addDepthSource(_program, _uniforms); if (config.generalEmulation.enableFragmentDepthWrite != 0 || config.frameBufferEmulation.N64DepthCompare != Config::dcDisable) - _uniforms.emplace_back(new URenderTarget(_program)); + _addRenderTarget(_program, _uniforms); if (m_glInfo.isGLESX && m_glInfo.noPerspective) { - _uniforms.emplace_back(new UClampMode(_program)); - _uniforms.emplace_back(new UPolygonOffset(_program)); + _addClampMode(_program, _uniforms); + _addPolygonOffset(_program, _uniforms); } - _uniforms.emplace_back(new UScreenCoordsScale(_program)); + _addScreenCoordsScale(_program, _uniforms); - _uniforms.emplace_back(new UColors(_program)); + _addColors(_program, _uniforms); if (_key.isRectKey()) - _uniforms.emplace_back(new URectColor(_program)); + _addRectColor(_program, _uniforms); if (_inputs.usesHwLighting()) - _uniforms.emplace_back(new ULights(_program)); -} - -CombinerProgramUniformFactory::CombinerProgramUniformFactory(const opengl::GLInfo & _glInfo) -: m_glInfo(_glInfo) -{ + _addLights(_program, _uniforms); } } diff --git a/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactory.h b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactory.h index f17ff1be..9f693a13 100644 --- a/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactory.h +++ b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactory.h @@ -4,18 +4,85 @@ namespace glsl { - class CombinerProgramUniformFactory - { - public: - CombinerProgramUniformFactory(const opengl::GLInfo & _glInfo); +class CombinerProgramUniformFactory { +public: + CombinerProgramUniformFactory(const opengl::GLInfo & _glInfo); + virtual ~CombinerProgramUniformFactory(); - void buildUniforms(GLuint _program, - const CombinerInputs & _inputs, - const CombinerKey & _key, - UniformGroups & _uniforms); + void buildUniforms(GLuint _program, + const CombinerInputs &_inputs, + const CombinerKey &_key, + UniformGroups &_uniforms); - private: - const opengl::GLInfo & m_glInfo; - }; +private: + virtual void _addNoiseTex(GLuint _program, UniformGroups &_uniforms) const = 0; + virtual void _addScreenSpaceTriangleInfo(GLuint _program, UniformGroups &_uniforms) const = 0; + + virtual void _addRasterInfo(GLuint _program, UniformGroups &_uniforms) const = 0; + + virtual void _addViewportInfo(GLuint _program, UniformGroups &_uniforms) const = 0; + + virtual void _addDepthTex(GLuint _program, UniformGroups &_uniforms) const = 0; + + virtual void _addDepthScale(GLuint _program, UniformGroups &_uniforms) const = 0; + + virtual void _addTextures(GLuint _program, UniformGroups &_uniforms) const = 0; + + virtual void _addMSAATextures(GLuint _program, UniformGroups &_uniforms) const = 0; + + virtual void _addFrameBufferInfo(GLuint _program, UniformGroups &_uniforms) const = 0; + + virtual void _addMipmap(GLuint _program, UniformGroups &_uniforms) const = 0; + + virtual void _addMipmap2(GLuint _program, UniformGroups &_uniforms) const = 0; + + virtual void _addTextureFetchMode(GLuint _program, UniformGroups &_uniforms) const = 0; + + virtual void _addTexturePersp(GLuint _program, UniformGroups &_uniforms) const = 0; + + virtual void _addTextureSize(GLuint _program, UniformGroups &_uniforms, bool _usesTile0, bool _usesTile1) const = 0; + + virtual void _addTextureParams(GLuint _program, UniformGroups &_uniforms, bool _usesTile0, bool _usesTile1) const = 0; + + virtual void _addClampWrapMirrorEngine(GLuint _program, UniformGroups &_uniforms, bool _usesTile0, bool _usesTile1) const = 0; + + virtual void _addFog(GLuint _program, UniformGroups &_uniforms) const = 0; + + virtual void _addBlendMode1Cycle(GLuint _program, UniformGroups &_uniforms) const = 0; + + virtual void _addBlendMode2Cycle(GLuint _program, UniformGroups &_uniforms) const = 0; + + virtual void _addBlendCvg(GLuint _program, UniformGroups &_uniforms) const = 0; + + virtual void _addDitherMode(GLuint _program, UniformGroups &_uniforms, bool _usesNoise) const = 0; + + virtual void _addScreenScale(GLuint _program, UniformGroups &_uniforms) const = 0; + + virtual void _addAlphaTestInfo(GLuint _program, UniformGroups &_uniforms) const = 0; + + virtual void _addZLutTexture(GLuint _program, UniformGroups &_uniforms) const = 0; + + virtual void _addDepthInfo(GLuint _program, UniformGroups &_uniforms) const = 0; + + virtual void _addDepthSource(GLuint _program, UniformGroups &_uniforms) const = 0; + + virtual void _addRenderTarget(GLuint _program, UniformGroups &_uniforms) const = 0; + + virtual void _addClampMode(GLuint _program, UniformGroups &_uniforms) const = 0; + + virtual void _addPolygonOffset(GLuint _program, UniformGroups &_uniforms) const = 0; + + virtual void _addScreenCoordsScale(GLuint _program, UniformGroups &_uniforms) const = 0; + + virtual void _addColors(GLuint _program, UniformGroups &_uniforms) const = 0; + + virtual void _addRectColor(GLuint _program, UniformGroups &_uniforms) const = 0; + + virtual void _addLights(GLuint _program, UniformGroups &_uniforms) const = 0; + +protected: + const opengl::GLInfo & m_glInfo; +}; } + diff --git a/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactoryAccurate.cpp b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactoryAccurate.cpp new file mode 100644 index 00000000..bca677e6 --- /dev/null +++ b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactoryAccurate.cpp @@ -0,0 +1,397 @@ +#include +#include +#include +#include "glsl_CombinerProgramUniformFactoryAccurate.h" +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef min +#undef min +#endif + +namespace glsl { + +class URasterInfo : public UniformGroup { +public: + URasterInfo(GLuint _program) { + LocateUniform(uVertexOffset); + LocateUniform(uTexCoordOffset[0]); + LocateUniform(uTexCoordOffset[1]); + LocateUniform(uUseTexCoordBounds); + LocateUniform(uTexCoordBounds0); + LocateUniform(uTexCoordBounds1); + } + + void update(bool _force) override { + const bool isNativeRes = config.frameBufferEmulation.nativeResFactor == 1 && config.video.multisampling == 0; + const bool isTexRect = dwnd().getDrawer().getDrawingState() == DrawingState::TexRect; + const bool useTexCoordBounds = isTexRect && !isNativeRes && config.graphics2D.enableTexCoordBounds; + /* At rasterization stage, the N64 places samples on the top left of the fragment while OpenGL */ + /* places them in the fragment center. As a result, a normal approach results in shifted texture */ + /* coordinates. In native resolution, this difference can be negated by shifting vertices by 0.5. */ + /* In higher resolutions, there are more samples than the game intends, so shifting is not very */ + /* effective. Still, an heuristic is applied to render texture rectangles as correctly as possible */ + /* in higher resolutions too. See issue #2324 for details. */ + const float vertexOffset = isNativeRes ? 0.5f : 0.0f; + float texCoordOffset[2][2] = { 0.0f, 0.0f }; + if (isTexRect && !isNativeRes) { + float scale[2] = { 0.0f, 0.0f }; + if (config.graphics2D.enableNativeResTexrects != 0 && gDP.otherMode.textureFilter != G_TF_POINT) { + scale[0] = scale[1] = 1.0f; + } else { + scale[0] = scale[1] = static_cast(config.frameBufferEmulation.nativeResFactor); + } + + for (int t = 0; t < 2; t++) { + const CachedTexture* _pTexture = textureCache().current[t]; + if (_pTexture != nullptr) { + if (config.frameBufferEmulation.nativeResFactor != 0) { + if (gDP.otherMode.textureFilter != G_TF_POINT && gDP.otherMode.cycleType != G_CYC_COPY) { + texCoordOffset[t][0] = -0.5f * gDP.lastTexRectInfo.dsdx; + texCoordOffset[t][1] = -0.5f * gDP.lastTexRectInfo.dtdy; + } else { + texCoordOffset[t][0] = (gDP.lastTexRectInfo.dsdx >= 0.0f ? -0.5f / scale[0] : -1.0f + 0.5f / scale[0]) * gDP.lastTexRectInfo.dsdx; + texCoordOffset[t][1] = (gDP.lastTexRectInfo.dtdy >= 0.0f ? -0.5f / scale[1] : -1.0f + 0.5f / scale[1]) * gDP.lastTexRectInfo.dtdy; + } + } else { + texCoordOffset[t][0] = (gDP.lastTexRectInfo.dsdx >= 0.0f ? 0.0f : -1.0f) * gDP.lastTexRectInfo.dsdx; + texCoordOffset[t][1] = (gDP.lastTexRectInfo.dtdy >= 0.0f ? 0.0f : -1.0f) * gDP.lastTexRectInfo.dtdy; + if (gDP.otherMode.textureFilter != G_TF_POINT && gDP.otherMode.cycleType != G_CYC_COPY) { + texCoordOffset[t][0] -= 0.5f; + texCoordOffset[t][1] -= 0.5f; + } + } + } + } + } + /* Hack for framebuffer textures. See #519 and #2112 */ + if ((config.generalEmulation.hacks & hack_fbTextureOffset) != 0) { + for (int t = 0; t < 2; t++) { + const CachedTexture* _pTexture = textureCache().current[t]; + if (_pTexture != nullptr) { + if (gDP.otherMode.textureFilter != G_TF_POINT && _pTexture->frameBufferTexture != CachedTexture::fbNone) { + texCoordOffset[t][0] -= 1.0f; + texCoordOffset[t][1] -= 1.0f; + } + } + } + } + float tcbounds[2][4] = {}; + if (useTexCoordBounds) { + f32 uls, lrs, ult, lrt, S, T; + for (int t = 0; t < 2; t++) { + const CachedTexture * _pTexture = textureCache().current[t]; + if (_pTexture != nullptr) { + S = _FIXED2FLOAT(gDP.lastTexRectInfo.s, 5); + T = _FIXED2FLOAT(gDP.lastTexRectInfo.t, 5); + uls = S + (ceilf(gDP.lastTexRectInfo.ulx) - gDP.lastTexRectInfo.ulx) * gDP.lastTexRectInfo.dsdx; + lrs = S + (ceilf(gDP.lastTexRectInfo.lrx) - gDP.lastTexRectInfo.ulx - 1.0f) * gDP.lastTexRectInfo.dsdx; + ult = T + (ceilf(gDP.lastTexRectInfo.uly) - gDP.lastTexRectInfo.uly) * gDP.lastTexRectInfo.dtdy; + lrt = T + (ceilf(gDP.lastTexRectInfo.lry) - gDP.lastTexRectInfo.uly - 1.0f) * gDP.lastTexRectInfo.dtdy; + tcbounds[t][0] = fmin(uls, lrs); + tcbounds[t][1] = fmin(ult, lrt); + tcbounds[t][2] = fmax(uls, lrs); + tcbounds[t][3] = fmax(ult, lrt); + } + } + } + + uVertexOffset.set(vertexOffset, vertexOffset, _force); + uTexCoordOffset[0].set(texCoordOffset[0][0], texCoordOffset[0][1], _force); + uTexCoordOffset[1].set(texCoordOffset[1][0], texCoordOffset[1][1], _force); + uUseTexCoordBounds.set(useTexCoordBounds ? 1 : 0, _force); + uTexCoordBounds0.set(tcbounds[0], _force); + uTexCoordBounds1.set(tcbounds[1], _force); + } + +private: + fv2Uniform uVertexOffset; + fv2Uniform uTexCoordOffset[2]; + iUniform uUseTexCoordBounds; + fv4Uniform uTexCoordBounds0; + fv4Uniform uTexCoordBounds1; +}; + +class UMipmap : public UniformGroup +{ +public: + UMipmap(GLuint _program) { + LocateUniform(uMinLod); + LocateUniform(uMaxTile); + LocateUniform(uEnableLod); + LocateUniform(uTextureDetail); + } + + void update(bool _force) override + { + uMinLod.set(gDP.primColor.m, _force); + const CachedTexture * _pTexture = textureCache().current[1]; + if (_pTexture == nullptr) + uMaxTile.set(gSP.texture.level, _force); + else + uMaxTile.set(_pTexture->max_level > 0 ? gSP.texture.level : std::min(gSP.texture.level, 1u), _force); + const int uCalcLOD = (gDP.otherMode.textureLOD == G_TL_LOD) ? 1 : 0; + uEnableLod.set(uCalcLOD, _force); + uTextureDetail.set(gDP.otherMode.textureDetail, _force); + } + +private: + fUniform uMinLod; + iUniform uMaxTile; + iUniform uEnableLod; + iUniform uTextureDetail; +}; + +class UTextureSize : public UniformGroup +{ +public: + UTextureSize(GLuint _program, bool _useT0, bool _useT1) + : m_useT0(_useT0) + , m_useT1(_useT1) + { + LocateUniform(uTextureSize[0]); + LocateUniform(uTextureSize[1]); + } + + void update(bool _force) override + { + TextureCache & cache = textureCache(); + if (m_useT0 && cache.current[0] != nullptr) + uTextureSize[0].set(static_cast(cache.current[0]->width), + static_cast(cache.current[0]->height), _force); + if (m_useT1 && cache.current[1] != nullptr) { + CachedTexture * pTexture = cache.current[1]; + if (pTexture->max_level == 0) + uTextureSize[1].set(static_cast(pTexture->width), + static_cast(pTexture->height), _force); + else + uTextureSize[1].set(static_cast(pTexture->mipmapAtlasWidth), + static_cast(pTexture->mipmapAtlasHeight), _force); + } + } + +private: + fv2Uniform uTextureSize[2]; + bool m_useT0; + bool m_useT1; +}; + +class UTextureParams : public UniformGroup +{ +public: + UTextureParams(GLuint _program, bool _useT0, bool _useT1) + { + m_useTile[0] = _useT0; + m_useTile[1] = _useT1; + LocateUniform(uTexScale); + LocateUniform(uCacheFrameBuffer); + } + + void update(bool _force) override + { + int nFB[2] = { 0, 0 }; + TextureCache & cache = textureCache(); + for (u32 t = 0; t < 2; ++t) { + if (!m_useTile[t]) + continue; + CachedTexture *_pTexture = cache.current[t]; + if (_pTexture != nullptr) { + nFB[t] = _pTexture->frameBufferTexture; + } + } + + uCacheFrameBuffer.set(nFB[0], nFB[1], _force); + uTexScale.set(gSP.texture.scales, gSP.texture.scalet, _force); + } + +private: + bool m_useTile[2]; + fv2Uniform uTexScale; + iv2Uniform uCacheFrameBuffer; +}; + +class UTextureEngine : public UniformGroup +{ +public: + UTextureEngine(GLuint _program, bool _useT0, bool _useT1) + { + m_useTile[0] = _useT0; + m_useTile[1] = _useT1; + LocateUniform(uTexWrap[0]); + LocateUniform(uTexWrap[1]); + LocateUniform(uTexClamp[0]); + LocateUniform(uTexClamp[1]); + LocateUniform(uTexWrapEn[0]); + LocateUniform(uTexWrapEn[1]); + LocateUniform(uTexClampEn[0]); + LocateUniform(uTexClampEn[1]); + LocateUniform(uTexMirrorEn[0]); + LocateUniform(uTexMirrorEn[1]); + LocateUniform(uTexSize[0]); + LocateUniform(uTexSize[1]); + LocateUniform(uShiftScale[0]); + LocateUniform(uShiftScale[1]); + LocateUniform(uTexOffset[0]); + LocateUniform(uTexOffset[1]); + LocateUniform(uHDRatio[0]); + LocateUniform(uHDRatio[1]); + LocateUniform(uCacheOffset[0]); + LocateUniform(uCacheOffset[1]); + LocateUniform(uBilinearOffset); + } + + void update(bool _force) override + { + std::array aTexWrap[2] = { { 1024.0f, 1024.0f }, { 1024.0f, 1024.0f } }; + std::array aTexClamp[2] = { { 1024.0f, 1024.0f }, { 1024.0f, 1024.0f } }; + std::array aTexWrapEn[2] = { { 0.0f, 0.0f }, { 0.0f, 0.0f } }; + std::array aTexClampEn[2] = { { 0.0f, 0.0f }, { 0.0f, 0.0f } }; + std::array aTexMirrorEn[2] = { { 0.0f, 0.0f }, { 0.0f,0.0f }}; + std::array aTexSize[2] = { { 1024.0f, 1024.0f }, { 1024.0f, 1024.0f } }; + + std::array aShiftScale[2] = { { 1.0f, 1.0f }, { 1.0f,1.0f } }; + std::array aTexOffset[2] = { { 0.0f, 0.0f }, { 0.0f, 0.0f } }; + + std::array aHDRatio[2] = { { 1.0f, 1.0f }, { 1.0f, 1.0f } }; + std::array aCacheOffset[2] = { { 0.0f, 0.0f }, { 0.0f, 0.0f } }; + + const float bilinearOffset = gDP.otherMode.textureFilter != G_TF_POINT && gDP.otherMode.cycleType != G_CYC_COPY ? 0.5f : 0.0f; + uBilinearOffset.set(bilinearOffset, bilinearOffset, _force); + + TextureCache & cache = textureCache(); + for (u32 t = 0; t < 2; ++t) { + if (!m_useTile[t]) + continue; + + const gDPTile * pTile = gSP.textureTile[t]; + CachedTexture * pTexture = cache.current[t]; + if (pTile == nullptr || pTexture == nullptr) + continue; + + aTexSize[t][0] = pTexture->width * pTexture->hdRatioS; + aTexSize[t][1] = pTexture->height * pTexture->hdRatioT; + + aShiftScale[t][0] = pTile->shifts > 10 ? static_cast(1 << (16 - pTile->shifts)) : 1.0f / static_cast(1 << pTile->shifts); + aShiftScale[t][1] = pTile->shiftt > 10 ? static_cast(1 << (16 - pTile->shiftt)) : 1.0f / static_cast(1 << pTile->shiftt); + + if (pTile->textureMode != TEXTUREMODE_BGIMAGE && pTile->textureMode != TEXTUREMODE_FRAMEBUFFER_BG) { + aTexOffset[t][0] = pTile->fuls; + aTexOffset[t][1] = pTile->fult; + } + + aHDRatio[t][0] = pTexture->hdRatioS; + aHDRatio[t][1] = pTexture->hdRatioT; + + aCacheOffset[t][0] = pTexture->offsetS * pTexture->hdRatioS; + aCacheOffset[t][1] = pTexture->offsetT * pTexture->hdRatioT; + + /* Not sure if special treatment of framebuffer textures is correct */ + if (pTexture->frameBufferTexture != CachedTexture::fbNone) + { + aTexClamp[t][0] = f32(pTexture->width) * pTexture->hdRatioS - 1.0f; + aTexClamp[t][1] = f32(pTexture->height) * pTexture->hdRatioT - 1.0f; + aTexWrapEn[t][0] = 0.0; + aTexWrapEn[t][1] = 0.0; + aTexClampEn[t][0] = 1.0; + aTexClampEn[t][1] = 1.0; + aTexMirrorEn[t][0] = 0.0; + aTexMirrorEn[t][1] = 0.0; + } else if (pTile->textureMode != TEXTUREMODE_NORMAL || g_debugger.isDebugMode()) { + aTexWrapEn[t][0] = 0.0; + aTexWrapEn[t][1] = 0.0; + aTexClampEn[t][0] = 0.0; + aTexClampEn[t][1] = 0.0; + aTexMirrorEn[t][0] = 0.0; + aTexMirrorEn[t][1] = 0.0; + } else { + aTexWrap[t][0] = f32(1 << pTile->masks) * pTexture->hdRatioS; + aTexWrap[t][1] = f32(1 << pTile->maskt) * pTexture->hdRatioT; + aTexClamp[t][0] = f32(pTile->lrs - pTile->uls + 1) * pTexture->hdRatioS - 1.0f; + aTexClamp[t][1] = f32(pTile->lrt - pTile->ult + 1) * pTexture->hdRatioT - 1.0f; + aTexWrapEn[t][0] = f32(pTile->masks == 0 ? 0 : 1); + aTexWrapEn[t][1] = f32(pTile->maskt == 0 ? 0 : 1); + aTexClampEn[t][0] = f32(gDP.otherMode.cycleType == G_CYC_COPY ? 0 : (pTile->masks == 0 ? 1 : pTile->clamps)); + aTexClampEn[t][1] = f32(gDP.otherMode.cycleType == G_CYC_COPY ? 0 : (pTile->maskt == 0 ? 1 : pTile->clampt)); + aTexMirrorEn[t][0] = f32(pTile->masks == 0 ? 0 : pTile->mirrors); + aTexMirrorEn[t][1] = f32(pTile->maskt == 0 ? 0 : pTile->mirrort); + } + + uTexWrap[t].set(aTexWrap[t][0], aTexWrap[t][1], _force); + uTexClamp[t].set(aTexClamp[t][0], aTexClamp[t][1], _force); + uTexWrapEn[t].set(aTexWrapEn[t][0], aTexWrapEn[t][1], _force); + uTexWrapEn[t].set(aTexWrapEn[t][0], aTexWrapEn[t][1], _force); + uTexClampEn[t].set(aTexClampEn[t][0], aTexClampEn[t][1], _force); + uTexMirrorEn[t].set(aTexMirrorEn[t][0], aTexMirrorEn[t][1], _force); + uTexSize[t].set(aTexSize[t][0], aTexSize[t][1], _force); + uShiftScale[t].set(aShiftScale[t][0], aShiftScale[t][1], _force); + uTexOffset[t].set(aTexOffset[t][0], aTexOffset[t][1], _force); + uHDRatio[t].set(aHDRatio[t][0], aHDRatio[t][1], _force); + uCacheOffset[t].set(aCacheOffset[t][0], aCacheOffset[t][1], _force); + } + + } + +private: + bool m_useTile[2]; + fv2Uniform uTexWrap[2]; + fv2Uniform uTexClamp[2]; + fv2Uniform uTexWrapEn[2]; + fv2Uniform uTexClampEn[2]; + fv2Uniform uTexMirrorEn[2]; + fv2Uniform uTexSize[2]; + fv2Uniform uShiftScale[2]; + fv2Uniform uTexOffset[2]; + fv2Uniform uHDRatio[2]; + fv2Uniform uCacheOffset[2]; + fv2Uniform uBilinearOffset; +}; + +/*---------------CombinerProgramUniformFactoryCommon-------------*/ + +void CombinerProgramUniformFactoryAccurate::_addRasterInfo(GLuint _program, UniformGroups &_uniforms) const +{ + _uniforms.emplace_back(new URasterInfo(_program)); +} + +void CombinerProgramUniformFactoryAccurate::_addMipmap(GLuint _program, UniformGroups &_uniforms) const +{ + _uniforms.emplace_back(new UMipmap(_program)); +} + +void CombinerProgramUniformFactoryAccurate::_addMipmap2(GLuint _program, UniformGroups &_uniforms) const +{ +} + +void CombinerProgramUniformFactoryAccurate::_addTextureSize(GLuint _program, UniformGroups &_uniforms, bool _usesTile0, bool _usesTile1) const +{ + _uniforms.emplace_back(new UTextureSize(_program, _usesTile0, _usesTile1)); +} + +void CombinerProgramUniformFactoryAccurate::_addTextureParams(GLuint _program, UniformGroups &_uniforms, bool _usesTile0, bool _usesTile1) const +{ + _uniforms.emplace_back(new UTextureParams(_program, _usesTile0, _usesTile1)); +} + +void CombinerProgramUniformFactoryAccurate::_addClampWrapMirrorEngine(GLuint _program, UniformGroups &_uniforms, bool _usesTile0, bool _usesTile1) const +{ + _uniforms.emplace_back(new UTextureEngine(_program, _usesTile0, _usesTile1)); +} + +CombinerProgramUniformFactoryAccurate::CombinerProgramUniformFactoryAccurate(const opengl::GLInfo & _glInfo) + : CombinerProgramUniformFactoryCommon(_glInfo) + , m_glInfo(_glInfo) +{ +} + +} diff --git a/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactoryAccurate.h b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactoryAccurate.h new file mode 100644 index 00000000..415e3d34 --- /dev/null +++ b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactoryAccurate.h @@ -0,0 +1,28 @@ +#pragma once +#include +#include "glsl_CombinerProgramImpl.h" +#include "glsl_CombinerProgramUniformFactoryCommon.h" + +namespace glsl { + class CombinerProgramUniformFactoryAccurate : public CombinerProgramUniformFactoryCommon { + + public: + CombinerProgramUniformFactoryAccurate(const opengl::GLInfo & _glInfo); + private: + + virtual void _addRasterInfo(GLuint _program, UniformGroups &_uniforms) const override; + + virtual void _addMipmap(GLuint _program, UniformGroups &_uniforms) const override; + + virtual void _addMipmap2(GLuint _program, UniformGroups &_uniforms) const override; + + virtual void _addTextureSize(GLuint _program, UniformGroups &_uniforms, bool _usesTile0, bool _usesTile1) const override; + + virtual void _addTextureParams(GLuint _program, UniformGroups &_uniforms, bool _usesTile0, bool _usesTile1) const override; + + virtual void _addClampWrapMirrorEngine(GLuint _program, UniformGroups &_uniforms, bool _usesTile0, bool _usesTile1) const override; + + const opengl::GLInfo &m_glInfo; + }; +} + diff --git a/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactoryCommon.cpp b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactoryCommon.cpp new file mode 100644 index 00000000..44f73306 --- /dev/null +++ b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactoryCommon.cpp @@ -0,0 +1,914 @@ +#include +#include "glsl_CombinerProgramUniformFactoryCommon.h" +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace glsl { + +/*---------------UniformGroup-------------*/ + +class UNoiseTex : public UniformGroup +{ +public: + UNoiseTex(GLuint _program) { + LocateUniform(uTexNoise); + } + + void update(bool _force) override + { + uTexNoise.set(int(graphics::textureIndices::NoiseTex), _force); + } + +private: + iUniform uTexNoise; +}; + +class UDepthTex : public UniformGroup +{ +public: + UDepthTex(GLuint _program) { + LocateUniform(uDepthTex); + } + + void update(bool _force) override + { + uDepthTex.set(int(graphics::textureIndices::DepthTex), _force); + } + +private: + iUniform uDepthTex; +}; + +class UZLutTexture : public UniformGroup +{ +public: + UZLutTexture(GLuint _program) { + LocateUniform(uZlutImage); + } + + void update(bool _force) override + { + uZlutImage.set(int(graphics::textureIndices::ZLUTTex), _force); + } + +private: + iUniform uZlutImage; +}; + +class UTextures : public UniformGroup +{ +public: + UTextures(GLuint _program) { + LocateUniform(uTex0); + LocateUniform(uTex1); + } + + void update(bool _force) override + { + uTex0.set(0, _force); + uTex1.set(1, _force); + } + +private: + iUniform uTex0; + iUniform uTex1; +}; + +class UMSAATextures : public UniformGroup +{ +public: + UMSAATextures(GLuint _program) { + LocateUniform(uMSTex0); + LocateUniform(uMSTex1); + LocateUniform(uMSAASamples); + } + + void update(bool _force) override + { + uMSTex0.set(int(graphics::textureIndices::MSTex[0]), _force); + uMSTex1.set(int(graphics::textureIndices::MSTex[1]), _force); + uMSAASamples.set(config.video.multisampling, _force); + } + +private: + iUniform uMSTex0; + iUniform uMSTex1; + iUniform uMSAASamples; +}; + +class UScreenSpaceTriangleInfo : public UniformGroup +{ +public: + UScreenSpaceTriangleInfo(GLuint _program) { + LocateUniform(uScreenSpaceTriangle); + } + + void update(bool _force) override + { + uScreenSpaceTriangle.set( + (dwnd().getDrawer().getDrawingState() == DrawingState::ScreenSpaceTriangle) ? 1 : 0, _force); + } + +private: + iUniform uScreenSpaceTriangle; +}; + +class UFrameBufferInfo : public UniformGroup +{ +public: + UFrameBufferInfo(GLuint _program) { + LocateUniform(uFbMonochrome); + LocateUniform(uFbFixedAlpha); + LocateUniform(uMSTexEnabled); + } + + void update(bool _force) override + { + int nFbMonochromeMode0 = 0, nFbMonochromeMode1 = 0; + int nFbFixedAlpha0 = 0, nFbFixedAlpha1 = 0; + int nMSTex0Enabled = 0, nMSTex1Enabled = 0; + TextureCache & cache = textureCache(); + if (cache.current[0] != nullptr && cache.current[0]->frameBufferTexture != CachedTexture::fbNone) { + if (cache.current[0]->size == G_IM_SIZ_8b) { + nFbMonochromeMode0 = 1; + if (gDP.otherMode.imageRead == 0) + nFbFixedAlpha0 = 1; + } else if (gSP.textureTile[0]->size == G_IM_SIZ_16b && gSP.textureTile[0]->format == G_IM_FMT_IA) { + nFbMonochromeMode0 = 2; + } else if ((config.generalEmulation.hacks & hack_ZeldaMonochrome) != 0 && + cache.current[0]->size == G_IM_SIZ_16b && + gSP.textureTile[0]->size == G_IM_SIZ_8b && + gSP.textureTile[0]->format == G_IM_FMT_CI) { + // Zelda monochrome effect + nFbMonochromeMode0 = 3; + nFbMonochromeMode1 = 3; + } + + nMSTex0Enabled = cache.current[0]->frameBufferTexture == CachedTexture::fbMultiSample ? 1 : 0; + } + if (cache.current[1] != nullptr && cache.current[1]->frameBufferTexture != CachedTexture::fbNone) { + if (cache.current[1]->size == G_IM_SIZ_8b) { + nFbMonochromeMode1 = 1; + if (gDP.otherMode.imageRead == 0) + nFbFixedAlpha1 = 1; + } + else if (gSP.textureTile[1]->size == G_IM_SIZ_16b && gSP.textureTile[1]->format == G_IM_FMT_IA) + nFbMonochromeMode1 = 2; + nMSTex1Enabled = cache.current[1]->frameBufferTexture == CachedTexture::fbMultiSample ? 1 : 0; + } + uFbMonochrome.set(nFbMonochromeMode0, nFbMonochromeMode1, _force); + uFbFixedAlpha.set(nFbFixedAlpha0, nFbFixedAlpha1, _force); + uMSTexEnabled.set(nMSTex0Enabled, nMSTex1Enabled, _force); + gDP.changed &= ~CHANGED_FB_TEXTURE; + } + +private: + iv2Uniform uFbMonochrome; + iv2Uniform uFbFixedAlpha; + iv2Uniform uMSTexEnabled; +}; + + +class UFog : public UniformGroup +{ +public: + UFog(GLuint _program) { + LocateUniform(uFogUsage); + LocateUniform(uFogScale); + } + + void update(bool _force) override + { + if (RSP.LLE) { + uFogUsage.set(0, _force); + return; + } + + int nFogUsage = ((gSP.geometryMode & G_FOG) != 0) ? 1 : 0; + if (GBI.getMicrocodeType() == F3DAM) { + const s16 fogMode = ((gSP.geometryMode >> 13) & 9) + 0xFFF8; + if (fogMode == 0) + nFogUsage = 1; + else if (fogMode > 0) + nFogUsage = 2; + } + uFogUsage.set(nFogUsage, _force); + uFogScale.set(gSP.fog.multiplierf, gSP.fog.offsetf, _force); + } + +private: + iUniform uFogUsage; + fv2Uniform uFogScale; +}; + +class UBlendMode1Cycle : public UniformGroup +{ +public: + UBlendMode1Cycle(GLuint _program) { + LocateUniform(uBlendMux1); + LocateUniform(uForceBlendCycle1); + } + + void update(bool _force) override + { + uBlendMux1.set(gDP.otherMode.c1_m1a, + gDP.otherMode.c1_m1b, + gDP.otherMode.c1_m2a, + gDP.otherMode.c1_m2b, + _force); + + const int forceBlend1 = (int)gDP.otherMode.forceBlender; + uForceBlendCycle1.set(forceBlend1, _force); + } + +private: + i4Uniform uBlendMux1; + iUniform uForceBlendCycle1; +}; + +class UBlendMode2Cycle : public UniformGroup +{ +public: + UBlendMode2Cycle(GLuint _program) { + LocateUniform(uBlendMux1); + LocateUniform(uBlendMux2); + LocateUniform(uForceBlendCycle1); + LocateUniform(uForceBlendCycle2); + } + + void update(bool _force) override + { + uBlendMux1.set(gDP.otherMode.c1_m1a, + gDP.otherMode.c1_m1b, + gDP.otherMode.c1_m2a, + gDP.otherMode.c1_m2b, + _force); + + uBlendMux2.set(gDP.otherMode.c2_m1a, + gDP.otherMode.c2_m1b, + gDP.otherMode.c2_m2a, + gDP.otherMode.c2_m2b, + _force); + + const int forceBlend1 = 1; + uForceBlendCycle1.set(forceBlend1, _force); + const int forceBlend2 = gDP.otherMode.forceBlender; + uForceBlendCycle2.set(forceBlend2, _force); + + if (!(graphics::Context::DualSourceBlending || graphics::Context::FramebufferFetchColor) || dwnd().getDrawer().isTexrectDrawerMode()) { + // Modes, which shader blender can't emulate + const u32 mode = _SHIFTR(gDP.otherMode.l, 16, 16); + switch (mode) { + case 0x0040: + // Mia Hamm Soccer + // clr_in * a_in + clr_mem * (1-a) + // clr_in * a_in + clr_in * (1-a) + case 0x0050: + // A Bug's Life + // clr_in * a_in + clr_mem * (1-a) + // clr_in * a_in + clr_mem * (1-a) + uForceBlendCycle1.set(0, _force); + uForceBlendCycle2.set(0, _force); + break; + case 0x0150: + // Tony Hawk + // clr_in * a_in + clr_mem * (1-a) + // clr_in * a_fog + clr_mem * (1-a_fog) + if ((config.generalEmulation.hacks & hack_TonyHawk) != 0) { + uForceBlendCycle1.set(0, _force); + uForceBlendCycle2.set(0, _force); + } + break; + } + } + + } + +private: + i4Uniform uBlendMux1; + i4Uniform uBlendMux2; + iUniform uForceBlendCycle1; + iUniform uForceBlendCycle2; +}; + +class UBlendCvg : public UniformGroup +{ +public: + UBlendCvg(GLuint _program) { + LocateUniform(uCvgDest); + LocateUniform(uBlendAlphaMode); + } + + void update(bool _force) override + { + uCvgDest.set(gDP.otherMode.cvgDest, _force); + if (dwnd().getDrawer().isTexrectDrawerMode()) + uBlendAlphaMode.set(2, _force); // No alpha blend in texrect drawing mode + else + uBlendAlphaMode.set(gDP.otherMode.forceBlender, _force); + } +private: + iUniform uCvgDest; + iUniform uBlendAlphaMode; +}; + +class UDitherMode : public UniformGroup +{ +public: + UDitherMode(GLuint _program, bool _usesNoise) + : m_usesNoise(_usesNoise) + { + LocateUniform(uAlphaCompareMode); + LocateUniform(uAlphaDitherMode); + LocateUniform(uColorDitherMode); + } + + void update(bool _force) override + { + if (gDP.otherMode.cycleType < G_CYC_COPY) { + uAlphaCompareMode.set(gDP.otherMode.alphaCompare, _force); + uAlphaDitherMode.set(gDP.otherMode.alphaDither, _force); + uColorDitherMode.set(gDP.otherMode.colorDither, _force); + } + else { + uAlphaCompareMode.set(0, _force); + uAlphaDitherMode.set(0, _force); + uColorDitherMode.set(0, _force); + } + + bool updateNoiseTex = m_usesNoise; + updateNoiseTex |= (gDP.otherMode.cycleType < G_CYC_COPY) && (gDP.otherMode.colorDither == G_CD_NOISE || gDP.otherMode.alphaDither == G_AD_NOISE || gDP.otherMode.alphaCompare == G_AC_DITHER); + if (updateNoiseTex) + g_noiseTexture.update(); + } + +private: + iUniform uAlphaCompareMode; + iUniform uAlphaDitherMode; + iUniform uColorDitherMode; + bool m_usesNoise; +}; + +class UScreenScale : public UniformGroup +{ +public: + UScreenScale(GLuint _program) { + LocateUniform(uScreenScale); + } + + void update(bool _force) override + { + if (dwnd().getDrawer().isTexrectDrawerMode()) { + uScreenScale.set(1.0f, 1.0f, _force); + return; + } + + FrameBuffer * pBuffer = frameBufferList().getCurrent(); + if (pBuffer == nullptr) + uScreenScale.set(dwnd().getScaleX(), dwnd().getScaleY(), _force); + else + uScreenScale.set(pBuffer->m_scale, pBuffer->m_scale, _force); + } + +private: + fv2Uniform uScreenScale; +}; + +class UTexturePersp : public UniformGroup +{ +public: + UTexturePersp(GLuint _program) { + LocateUniform(uTexturePersp); + } + + void update(bool _force) override + { + const u32 texturePersp = (RSP.LLE || GBI.isTexturePersp()) ? gDP.otherMode.texturePersp : 1U; + uTexturePersp.set(texturePersp, _force); + } + +private: + iUniform uTexturePersp; +}; + +class UTextureFetchMode : public UniformGroup +{ +public: + UTextureFetchMode(GLuint _program) { + LocateUniform(uTextureFilterMode); + LocateUniform(uTextureFormat); + LocateUniform(uTextureConvert); + LocateUniform(uConvertParams); + } + + void update(bool _force) override + { + int textureFilter = gDP.otherMode.textureFilter; + uTextureFilterMode.set(textureFilter, _force); + uTextureFormat.set(gSP.textureTile[0]->format, gSP.textureTile[1]->format, _force); + uTextureConvert.set(gDP.otherMode.convert_one, _force); + if (gDP.otherMode.bi_lerp0 == 0 || gDP.otherMode.bi_lerp1 == 0) + uConvertParams.set(gDP.convert.k0, gDP.convert.k1, gDP.convert.k2, gDP.convert.k3, _force); + } + +private: + iUniform uTextureFilterMode; + iv2Uniform uTextureFormat; + iUniform uTextureConvert; + i4Uniform uConvertParams; +}; + +class UAlphaTestInfo : public UniformGroup +{ +public: + UAlphaTestInfo(GLuint _program) { + LocateUniform(uEnableAlphaTest); + LocateUniform(uAlphaCvgSel); + LocateUniform(uCvgXAlpha); + LocateUniform(uAlphaTestValue); + } + + void update(bool _force) override + { + if (gDP.otherMode.cycleType == G_CYC_FILL) { + uEnableAlphaTest.set(0, _force); + uAlphaCvgSel.set(0, _force); + + } else if (gDP.otherMode.cycleType == G_CYC_COPY) { + uAlphaCvgSel.set(0, _force); + if (gDP.otherMode.alphaCompare & G_AC_THRESHOLD) { + uEnableAlphaTest.set(1, _force); + uAlphaTestValue.set(0.5f, _force); + } else { + uEnableAlphaTest.set(0, _force); + } + } else if ((gDP.otherMode.alphaCompare & G_AC_THRESHOLD) != 0) { + uEnableAlphaTest.set(1, _force); + uAlphaTestValue.set(gDP.blendColor.a, _force); + uAlphaCvgSel.set(gDP.otherMode.alphaCvgSel, _force); + } else { + uEnableAlphaTest.set(0, _force); + uAlphaCvgSel.set(gDP.otherMode.alphaCvgSel, _force); + } + + uCvgXAlpha.set(gDP.otherMode.cvgXAlpha, _force); + } + +private: + iUniform uEnableAlphaTest; + iUniform uAlphaCvgSel; + iUniform uCvgXAlpha; + fUniform uAlphaTestValue; +}; + +class UViewportInfo : public UniformGroup +{ +public: + UViewportInfo(GLuint _program) { + LocateUniform(uVTrans); + LocateUniform(uVScale); + LocateUniform(uAdjustTrans); + LocateUniform(uAdjustScale); + } + + void update(bool _force) override + { + const bool isOrthographicProjection = gSP.matrix.projection[3][2] == -1.f; + float adjustTrans[2] = { 0.0f, 0.0f }; + float adjustScale[2] = { 1.0f, 1.0f }; + if (dwnd().isAdjustScreen() && (gDP.colorImage.width > VI.width * 98 / 100)) { + if (isOrthographicProjection) { + adjustScale[1] = 1.0f / dwnd().getAdjustScale(); + adjustTrans[1] = static_cast(gDP.colorImage.width) * 3.0f / 4.0f * (1.0f - adjustScale[1]) / 2.0f; + } else { + adjustScale[0] = dwnd().getAdjustScale(); + adjustTrans[0] = static_cast(gDP.colorImage.width) * (1.0f - adjustScale[0]) / 2.0f; + } + } + uVTrans.set(gSP.viewport.vtrans[0], gSP.viewport.vtrans[1], _force); + uVScale.set(gSP.viewport.vscale[0], -gSP.viewport.vscale[1], _force); + uAdjustTrans.set(adjustTrans[0], adjustTrans[1], _force); + uAdjustScale.set(adjustScale[0], adjustScale[1], _force); + } + +private: + fv2Uniform uVTrans; + fv2Uniform uVScale; + fv2Uniform uAdjustTrans; + fv2Uniform uAdjustScale; +}; + +class UDepthScale : public UniformGroup +{ +public: + UDepthScale(GLuint _program) { + LocateUniform(uDepthScale); + } + + void update(bool _force) override + { + if (RSP.LLE) + uDepthScale.set(0.5f, 0.5f, _force); + else + uDepthScale.set(gSP.viewport.vscale[2], gSP.viewport.vtrans[2], _force); + } + +private: + fv2Uniform uDepthScale; +}; + +class UDepthInfo : public UniformGroup +{ +public: + UDepthInfo(GLuint _program) { + LocateUniform(uEnableDepth); + LocateUniform(uEnableDepthCompare); + LocateUniform(uEnableDepthUpdate); + LocateUniform(uDepthMode); + LocateUniform(uDepthSource); + LocateUniform(uPrimDepth); + LocateUniform(uDeltaZ); + } + + void update(bool _force) override + { + FrameBuffer * pBuffer = frameBufferList().getCurrent(); + if (pBuffer == nullptr || pBuffer->m_pDepthBuffer == nullptr) + return; + + const bool nDepthEnabled = ((gSP.geometryMode & G_ZBUFFER) || gDP.otherMode.depthSource == G_ZS_PRIM) && + gDP.otherMode.cycleType <= G_CYC_2CYCLE; + uEnableDepth.set(nDepthEnabled ? 1 : 0, _force); + if (nDepthEnabled) { + uEnableDepthCompare.set(gDP.otherMode.depthCompare, _force); + uEnableDepthUpdate.set(gDP.otherMode.depthUpdate, _force); + } else { + uEnableDepthCompare.set(0, _force); + uEnableDepthUpdate.set(0, _force); + } + uDepthMode.set(gDP.otherMode.depthMode, _force); + uDepthSource.set(gDP.otherMode.depthSource, _force); + if (gDP.otherMode.depthSource == G_ZS_PRIM) { + uDeltaZ.set(gDP.primDepth.deltaZ, _force); + uPrimDepth.set(gDP.primDepth.z, _force); + } + } + +private: + iUniform uEnableDepth; + iUniform uEnableDepthCompare; + iUniform uEnableDepthUpdate; + iUniform uDepthMode; + iUniform uDepthSource; + fUniform uPrimDepth; + fUniform uDeltaZ; +}; + +class UDepthSource : public UniformGroup +{ +public: + UDepthSource(GLuint _program) { + LocateUniform(uDepthSource); + LocateUniform(uPrimDepth); + } + + void update(bool _force) override + { + uDepthSource.set(gDP.otherMode.depthSource, _force); + if (gDP.otherMode.depthSource == G_ZS_PRIM) + uPrimDepth.set(gDP.primDepth.z, _force); + } + +private: + iUniform uDepthSource; + fUniform uPrimDepth; +}; + +class URenderTarget : public UniformGroup +{ +public: + URenderTarget(GLuint _program) { + LocateUniform(uRenderTarget); + } + + void update(bool _force) override + { + int renderTarget = 0; + if (isCurrentColorImageDepthImage()) { + renderTarget = isDepthCompareEnabled() ? 2 : 1; + } + uRenderTarget.set(renderTarget, _force); + } + +private: + iUniform uRenderTarget; +}; + +class UClampMode : public UniformGroup +{ +public: + UClampMode(GLuint _program) { + LocateUniform(uClampMode); + } + + void update(bool _force) override + { + int clampMode = -1; + switch (gfxContext.getClampMode()) + { + case graphics::ClampMode::ClippingEnabled: + clampMode = 0; + break; + case graphics::ClampMode::NoNearPlaneClipping: + clampMode = 1; + break; + case graphics::ClampMode::NoClipping: + clampMode = 2; + break; + } + uClampMode.set(clampMode, _force); + } + +private: + iUniform uClampMode; +}; + +class UPolygonOffset : public UniformGroup +{ +public: + UPolygonOffset(GLuint _program) { + LocateUniform(uPolygonOffset); + } + + void update(bool _force) override + { + f32 offset = gfxContext.isEnabled(graphics::enable::POLYGON_OFFSET_FILL) ? 0.003f : 0.0f; + uPolygonOffset.set(offset, _force); + } + +private: + fUniform uPolygonOffset; +}; + +class UScreenCoordsScale : public UniformGroup +{ +public: + UScreenCoordsScale(GLuint _program) { + LocateUniform(uScreenCoordsScale); + } + + void update(bool _force) override + { + f32 scaleX, scaleY; + calcCoordsScales(frameBufferList().getCurrent(), scaleX, scaleY); + uScreenCoordsScale.set(2.0f*scaleX, -2.0f*scaleY, _force); + } + +private: + fv2Uniform uScreenCoordsScale; +}; + +class UColors : public UniformGroup +{ +public: + UColors(GLuint _program) { + LocateUniform(uFogColor); + LocateUniform(uCenterColor); + LocateUniform(uScaleColor); + LocateUniform(uBlendColor); + LocateUniform(uEnvColor); + LocateUniform(uPrimColor); + LocateUniform(uPrimLod); + LocateUniform(uK4); + LocateUniform(uK5); + } + + void update(bool _force) override + { + uFogColor.set(&gDP.fogColor.r, _force); + uCenterColor.set(&gDP.key.center.r, _force); + uScaleColor.set(&gDP.key.scale.r, _force); + uBlendColor.set(&gDP.blendColor.r, _force); + uEnvColor.set(&gDP.envColor.r, _force); + uPrimColor.set(&gDP.primColor.r, _force); + uPrimLod.set(gDP.primColor.l, _force); + uK4.set(_FIXED2FLOATCOLOR(gDP.convert.k4, 8 ), _force); + uK5.set(_FIXED2FLOATCOLOR(gDP.convert.k5, 8 ), _force); + } + +private: + fv4Uniform uFogColor; + fv4Uniform uCenterColor; + fv4Uniform uScaleColor; + fv4Uniform uBlendColor; + fv4Uniform uEnvColor; + fv4Uniform uPrimColor; + fUniform uPrimLod; + fUniform uK4; + fUniform uK5; +}; + +class URectColor : public UniformGroup +{ +public: + URectColor(GLuint _program) { + LocateUniform(uRectColor); + } + + void update(bool _force) override + { + uRectColor.set(&gDP.rectColor.r, _force); + } + +private: + fv4Uniform uRectColor; +}; + +class ULights : public UniformGroup +{ +public: + ULights(GLuint _program) + { + char buf[32]; + for (s32 i = 0; i < 8; ++i) { + sprintf(buf, "uLightDirection[%d]", i); + uLightDirection[i].loc = glGetUniformLocation(_program, buf); + sprintf(buf, "uLightColor[%d]", i); + uLightColor[i].loc = glGetUniformLocation(_program, buf); + } + } + + void update(bool _force) override + { + for (u32 i = 0; i <= gSP.numLights; ++i) { + uLightDirection[i].set(gSP.lights.xyz[i], _force); + uLightColor[i].set(gSP.lights.rgb[i], _force); + } + } + +private: + fv3Uniform uLightDirection[8]; + fv3Uniform uLightColor[8]; +}; + + +/*---------------CombinerProgramUniformFactoryCommon-------------*/ + +void CombinerProgramUniformFactoryCommon::_addNoiseTex(GLuint _program, UniformGroups &_uniforms) const +{ + _uniforms.emplace_back(new UNoiseTex(_program)); +} + +void CombinerProgramUniformFactoryCommon::_addScreenSpaceTriangleInfo(GLuint _program, UniformGroups &_uniforms) const +{ + _uniforms.emplace_back(new UScreenSpaceTriangleInfo(_program)); +} + +void CombinerProgramUniformFactoryCommon::_addRasterInfo(GLuint _program, UniformGroups &_uniforms) const +{ + _uniforms.emplace_back(new UScreenSpaceTriangleInfo(_program)); +} + +void CombinerProgramUniformFactoryCommon::_addViewportInfo(GLuint _program, UniformGroups &_uniforms) const +{ + _uniforms.emplace_back(new UViewportInfo(_program)); +} + +void CombinerProgramUniformFactoryCommon::_addDepthTex(GLuint _program, UniformGroups &_uniforms) const +{ + _uniforms.emplace_back(new UDepthTex(_program)); +} + +void CombinerProgramUniformFactoryCommon::_addDepthScale(GLuint _program, UniformGroups &_uniforms) const +{ + _uniforms.emplace_back(new UDepthScale(_program)); +} + +void CombinerProgramUniformFactoryCommon::_addTextures(GLuint _program, UniformGroups &_uniforms) const +{ + _uniforms.emplace_back(new UTextures(_program)); +} + +void CombinerProgramUniformFactoryCommon::_addMSAATextures(GLuint _program, UniformGroups &_uniforms) const +{ + _uniforms.emplace_back(new UMSAATextures(_program)); +} + +void CombinerProgramUniformFactoryCommon::_addFrameBufferInfo(GLuint _program, UniformGroups &_uniforms) const +{ + _uniforms.emplace_back(new UFrameBufferInfo(_program)); +} + +void CombinerProgramUniformFactoryCommon::_addTextureFetchMode(GLuint _program, UniformGroups &_uniforms) const +{ + _uniforms.emplace_back(new UTextureFetchMode(_program)); +} + +void CombinerProgramUniformFactoryCommon::_addTexturePersp(GLuint _program, UniformGroups &_uniforms) const +{ + _uniforms.emplace_back(new UTexturePersp(_program)); +} + +void CombinerProgramUniformFactoryCommon::_addFog(GLuint _program, UniformGroups &_uniforms) const +{ + _uniforms.emplace_back(new UFog(_program)); +} + +void CombinerProgramUniformFactoryCommon::_addBlendMode1Cycle(GLuint _program, UniformGroups &_uniforms) const +{ + _uniforms.emplace_back(new UBlendMode1Cycle(_program)); +} + +void CombinerProgramUniformFactoryCommon::_addBlendMode2Cycle(GLuint _program, UniformGroups &_uniforms) const +{ + _uniforms.emplace_back(new UBlendMode2Cycle(_program)); +} + +void CombinerProgramUniformFactoryCommon::_addBlendCvg(GLuint _program, UniformGroups &_uniforms) const +{ + _uniforms.emplace_back(new UBlendCvg(_program)); +} + +void CombinerProgramUniformFactoryCommon::_addDitherMode(GLuint _program, UniformGroups &_uniforms, bool _usesNoise) const +{ + _uniforms.emplace_back(new UDitherMode(_program, _usesNoise)); +} + +void CombinerProgramUniformFactoryCommon::_addScreenScale(GLuint _program, UniformGroups &_uniforms) const +{ + _uniforms.emplace_back(new UScreenScale(_program)); +} + +void CombinerProgramUniformFactoryCommon::_addAlphaTestInfo(GLuint _program, UniformGroups &_uniforms) const +{ + _uniforms.emplace_back(new UAlphaTestInfo(_program)); +} + +void CombinerProgramUniformFactoryCommon::_addZLutTexture(GLuint _program, UniformGroups &_uniforms) const +{ + _uniforms.emplace_back(new UZLutTexture(_program)); +} + +void CombinerProgramUniformFactoryCommon::_addDepthInfo(GLuint _program, UniformGroups &_uniforms) const +{ + _uniforms.emplace_back(new UDepthInfo(_program)); +} + +void CombinerProgramUniformFactoryCommon::_addDepthSource(GLuint _program, UniformGroups &_uniforms) const +{ + _uniforms.emplace_back(new UDepthSource(_program)); +} + +void CombinerProgramUniformFactoryCommon::_addRenderTarget(GLuint _program, UniformGroups &_uniforms) const +{ + _uniforms.emplace_back(new URenderTarget(_program)); +} + +void CombinerProgramUniformFactoryCommon::_addClampMode(GLuint _program, UniformGroups &_uniforms) const +{ + _uniforms.emplace_back(new UClampMode(_program)); +} + +void CombinerProgramUniformFactoryCommon::_addPolygonOffset(GLuint _program, UniformGroups &_uniforms) const +{ + _uniforms.emplace_back(new UPolygonOffset(_program)); +} + +void CombinerProgramUniformFactoryCommon::_addScreenCoordsScale(GLuint _program, UniformGroups &_uniforms) const +{ + _uniforms.emplace_back(new UScreenCoordsScale(_program)); +} + +void CombinerProgramUniformFactoryCommon::_addColors(GLuint _program, UniformGroups &_uniforms) const +{ + _uniforms.emplace_back(new UColors(_program)); +} + +void CombinerProgramUniformFactoryCommon::_addRectColor(GLuint _program, UniformGroups &_uniforms) const +{ + _uniforms.emplace_back(new URectColor(_program)); +} + +void CombinerProgramUniformFactoryCommon::_addLights(GLuint _program, UniformGroups &_uniforms) const +{ + _uniforms.emplace_back(new ULights(_program)); +} + +CombinerProgramUniformFactoryCommon::CombinerProgramUniformFactoryCommon(const opengl::GLInfo & _glInfo) +: CombinerProgramUniformFactory(_glInfo) +{ + +} + +} diff --git a/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactoryCommon.h b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactoryCommon.h new file mode 100644 index 00000000..3457b8e8 --- /dev/null +++ b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactoryCommon.h @@ -0,0 +1,161 @@ +#pragma once +#include "glsl_CombinerProgramUniformFactory.h" + +namespace glsl { + +/*---------------Uniform-------------*/ + +struct iUniform { + GLint loc = -1; + int val = -999; + void set(int _val, bool _force) { + if (loc >= 0 && (_force || val != _val)) { + val = _val; + glUniform1i(loc, _val); + } + } +}; + +struct fUniform { + GLint loc = -1; + float val = -9999.9f; + void set(float _val, bool _force) { + if (loc >= 0 && (_force || val != _val)) { + val = _val; + glUniform1f(loc, _val); + } + } +}; + +struct fv2Uniform { + GLint loc = -1; + float val1 = -9999.9f, val2 = -9999.9f; + void set(float _val1, float _val2, bool _force) { + if (loc >= 0 && (_force || val1 != _val1 || val2 != _val2)) { + val1 = _val1; + val2 = _val2; + glUniform2f(loc, _val1, _val2); + } + } +}; + +struct fv3Uniform { + GLint loc = -1; + float val[3]; + void set(float * _pVal, bool _force) { + const size_t szData = sizeof(float)* 3; + if (loc >= 0 && (_force || memcmp(val, _pVal, szData) != 0)) { + memcpy(val, _pVal, szData); + glUniform3fv(loc, 1, _pVal); + } + } +}; + +struct fv4Uniform { + GLint loc = -1; + float val[4]; + void set(float * _pVal, bool _force) { + const size_t szData = sizeof(float)* 4; + if (loc >= 0 && (_force || memcmp(val, _pVal, szData) != 0)) { + memcpy(val, _pVal, szData); + glUniform4fv(loc, 1, _pVal); + } + } +}; + +struct iv2Uniform { + GLint loc = -1; + int val1 = -999, val2 = -999; + void set(int _val1, int _val2, bool _force) { + if (loc >= 0 && (_force || val1 != _val1 || val2 != _val2)) { + val1 = _val1; + val2 = _val2; + glUniform2i(loc, _val1, _val2); + } + } +}; + +struct i4Uniform { + GLint loc = -1; + int val0 = -999, val1 = -999, val2 = -999, val3 = -999; + void set(int _val0, int _val1, int _val2, int _val3, bool _force) { + if (loc < 0) + return; + if (_force || _val0 != val0 || _val1 != val1 || _val2 != val2 || _val3 != val3) { + val0 = _val0; + val1 = _val1; + val2 = _val2; + val3 = _val3; + glUniform4i(loc, val0, val1, val2, val3); + } + } +}; + +#define LocateUniform(A) \ +A.loc = glGetUniformLocation(_program, #A); + +class CombinerProgramUniformFactoryCommon : public CombinerProgramUniformFactory +{ +public: + CombinerProgramUniformFactoryCommon(const opengl::GLInfo & _glInfo); + +private: + void _addNoiseTex(GLuint _program, UniformGroups &_uniforms) const override; + + void _addScreenSpaceTriangleInfo(GLuint _program, UniformGroups &_uniforms) const override; + + void _addRasterInfo(GLuint _program, UniformGroups &_uniforms) const override; + + void _addViewportInfo(GLuint _program, UniformGroups &_uniforms) const override; + + void _addDepthTex(GLuint _program, UniformGroups &_uniforms) const override; + + void _addDepthScale(GLuint _program, UniformGroups &_uniforms) const override; + + void _addTextures(GLuint _program, UniformGroups &_uniforms) const override; + + void _addMSAATextures(GLuint _program, UniformGroups &_uniforms) const override; + + void _addFrameBufferInfo(GLuint _program, UniformGroups &_uniforms) const override; + + void _addTextureFetchMode(GLuint _program, UniformGroups &_uniforms) const override; + + void _addTexturePersp(GLuint _program, UniformGroups &_uniforms) const override; + + void _addFog(GLuint _program, UniformGroups &_uniforms) const override; + + void _addBlendMode1Cycle(GLuint _program, UniformGroups &_uniforms) const override; + + void _addBlendMode2Cycle(GLuint _program, UniformGroups &_uniforms) const override; + + void _addBlendCvg(GLuint _program, UniformGroups &_uniforms) const override; + + void _addDitherMode(GLuint _program, UniformGroups &_uniforms, bool _usesNoise) const override; + + void _addScreenScale(GLuint _program, UniformGroups &_uniforms) const override; + + void _addAlphaTestInfo(GLuint _program, UniformGroups &_uniforms) const override; + + void _addZLutTexture(GLuint _program, UniformGroups &_uniforms) const override; + + void _addDepthInfo(GLuint _program, UniformGroups &_uniforms) const override; + + void _addDepthSource(GLuint _program, UniformGroups &_uniforms) const override; + + void _addRenderTarget(GLuint _program, UniformGroups &_uniforms) const override; + + void _addClampMode(GLuint _program, UniformGroups &_uniforms) const override; + + void _addPolygonOffset(GLuint _program, UniformGroups &_uniforms) const override; + + void _addScreenCoordsScale(GLuint _program, UniformGroups &_uniforms) const override; + + void _addColors(GLuint _program, UniformGroups &_uniforms) const override; + + void _addRectColor(GLuint _program, UniformGroups &_uniforms) const override; + + void _addLights(GLuint _program, UniformGroups &_uniforms) const override; +}; + +} + diff --git a/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactoryFast.cpp b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactoryFast.cpp new file mode 100644 index 00000000..d06f67be --- /dev/null +++ b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactoryFast.cpp @@ -0,0 +1,433 @@ +#include +#include +#include +#include "glsl_CombinerProgramUniformFactoryFast.h" +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef min +#undef min +#endif + +namespace glsl { + +class URasterInfoFast : public UniformGroup { +public: + URasterInfoFast(GLuint _program) { + LocateUniform(uVertexOffset); + LocateUniform(uTexCoordOffset[0]); + LocateUniform(uTexCoordOffset[1]); + LocateUniform(uUseTexCoordBounds); + LocateUniform(uTexCoordBounds0); + LocateUniform(uTexCoordBounds1); + } + + void update(bool _force) override { + const bool isNativeRes = config.frameBufferEmulation.nativeResFactor == 1 && config.video.multisampling == 0; + const bool isTexRect = dwnd().getDrawer().getDrawingState() == DrawingState::TexRect; + const bool useTexCoordBounds = isTexRect && !isNativeRes && config.graphics2D.enableTexCoordBounds; + /* At rasterization stage, the N64 places samples on the top left of the fragment while OpenGL */ + /* places them in the fragment center. As a result, a normal approach results in shifted texture */ + /* coordinates. In native resolution, this difference can be negated by shifting vertices by 0.5. */ + /* In higher resolutions, there are more samples than the game intends, so shifting is not very */ + /* effective. Still, an heuristic is applied to render texture rectangles as correctly as possible */ + /* in higher resolutions too. See issue #2324 for details. */ + const float vertexOffset = isNativeRes ? 0.5f : 0.0f; + float texCoordOffset[2][2] = { 0.0f, 0.0f }; + if (isTexRect && !isNativeRes) { + float scale[2] = { 0.0f, 0.0f }; + if (config.graphics2D.enableNativeResTexrects != 0 && gDP.otherMode.textureFilter != G_TF_POINT) { + scale[0] = scale[1] = 1.0f; + } else { + scale[0] = scale[1] = static_cast(config.frameBufferEmulation.nativeResFactor); + } + + for (int t = 0; t < 2; t++) { + const CachedTexture* _pTexture = textureCache().current[t]; + if (_pTexture != nullptr) { + if (config.frameBufferEmulation.nativeResFactor != 0) { + texCoordOffset[t][0] = (gDP.lastTexRectInfo.dsdx >= 0.0f ? -0.5f / scale[0] : -1.0f + 0.5f / scale[0]) * gDP.lastTexRectInfo.dsdx * _pTexture->hdRatioS; + texCoordOffset[t][1] = (gDP.lastTexRectInfo.dtdy >= 0.0f ? -0.5f / scale[1] : -1.0f + 0.5f / scale[1]) * gDP.lastTexRectInfo.dtdy * _pTexture->hdRatioT; + } else { + texCoordOffset[t][0] = (gDP.lastTexRectInfo.dsdx >= 0.0f ? 0.0f : -1.0f) * gDP.lastTexRectInfo.dsdx * _pTexture->hdRatioS; + texCoordOffset[t][1] = (gDP.lastTexRectInfo.dtdy >= 0.0f ? 0.0f : -1.0f) * gDP.lastTexRectInfo.dtdy * _pTexture->hdRatioT; + if (gDP.otherMode.textureFilter != G_TF_POINT && gDP.otherMode.cycleType != G_CYC_COPY) { + texCoordOffset[t][0] -= 0.5f; + texCoordOffset[t][1] -= 0.5f; + } + } + } + } + } + /* Hack for framebuffer textures. See #519 and #2112 */ + if ((config.generalEmulation.hacks & hack_fbTextureOffset) != 0) { + for (int t = 0; t < 2; t++) { + const CachedTexture* _pTexture = textureCache().current[t]; + if (_pTexture != nullptr) { + if (gDP.otherMode.textureFilter != G_TF_POINT && _pTexture->frameBufferTexture != CachedTexture::fbNone) { + texCoordOffset[t][0] -= 1.0f; + texCoordOffset[t][1] -= 1.0f; + } + } + } + } + float tcbounds[2][4] = {}; + if (useTexCoordBounds) { + f32 uls, lrs, ult, lrt, S, T, shiftScaleS, shiftScaleT; + s16 shiftedS, shiftedT; + u32 shifts, shiftt; + for (int t = 0; t < 2; t++) { + const CachedTexture * _pTexture = textureCache().current[t]; + const gDPTile * _pTile = gSP.textureTile[t]; + if (_pTexture != nullptr && _pTile != nullptr){ + if (_pTile->shifts > 10) { + shifts = 16 - _pTile->shifts; + shiftedS = static_cast(gDP.lastTexRectInfo.s << shifts); + shiftScaleS = static_cast(1 << shifts); + } else { + shifts = _pTile->shifts; + shiftedS = static_cast(gDP.lastTexRectInfo.s >> shifts); + shiftScaleS = 1.0f / static_cast(1 << shifts); + } + if (_pTile->shiftt > 10) { + shiftt = 16 - _pTile->shiftt; + shiftedT = static_cast(gDP.lastTexRectInfo.t << shiftt); + shiftScaleT = static_cast(1 << shiftt); + } else { + shiftt = _pTile->shiftt; + shiftedT = static_cast(gDP.lastTexRectInfo.t >> shiftt); + shiftScaleT = 1.0f / static_cast(1 << shiftt); + } + + S = _FIXED2FLOAT(shiftedS, 5); + T = _FIXED2FLOAT(shiftedT, 5); + uls = S + (ceilf(gDP.lastTexRectInfo.ulx) - gDP.lastTexRectInfo.ulx) * gDP.lastTexRectInfo.dsdx * shiftScaleS; + lrs = S + (ceilf(gDP.lastTexRectInfo.lrx) - gDP.lastTexRectInfo.ulx - 1.0f) * gDP.lastTexRectInfo.dsdx * shiftScaleS; + ult = T + (ceilf(gDP.lastTexRectInfo.uly) - gDP.lastTexRectInfo.uly) * gDP.lastTexRectInfo.dtdy * shiftScaleT; + lrt = T + (ceilf(gDP.lastTexRectInfo.lry) - gDP.lastTexRectInfo.uly - 1.0f) * gDP.lastTexRectInfo.dtdy * shiftScaleT; + + tcbounds[t][0] = (fmin(uls, lrs) - _pTile->fuls) * _pTexture->hdRatioS; + tcbounds[t][1] = (fmin(ult, lrt) - _pTile->fult) * _pTexture->hdRatioT; + tcbounds[t][2] = (fmax(uls, lrs) - _pTile->fuls) * _pTexture->hdRatioS; + tcbounds[t][3] = (fmax(ult, lrt) - _pTile->fult) * _pTexture->hdRatioT; + if (_pTexture->frameBufferTexture != CachedTexture::fbNone) { + tcbounds[t][0] += _pTexture->offsetS * _pTexture->hdRatioS; + tcbounds[t][1] += _pTexture->offsetT * _pTexture->hdRatioT; + tcbounds[t][2] += _pTexture->offsetS * _pTexture->hdRatioS; + tcbounds[t][3] += _pTexture->offsetT * _pTexture->hdRatioT; + } + } + } + } + + uVertexOffset.set(vertexOffset, vertexOffset, _force); + uTexCoordOffset[0].set(texCoordOffset[0][0], texCoordOffset[0][1], _force); + uTexCoordOffset[1].set(texCoordOffset[1][0], texCoordOffset[1][1], _force); + uUseTexCoordBounds.set(useTexCoordBounds ? 1 : 0, _force); + uTexCoordBounds0.set(tcbounds[0], _force); + uTexCoordBounds1.set(tcbounds[1], _force); + } + +private: + fv2Uniform uVertexOffset; + fv2Uniform uTexCoordOffset[2]; + iUniform uUseTexCoordBounds; + fv4Uniform uTexCoordBounds0; + fv4Uniform uTexCoordBounds1; +}; + +class UMipmap1 : public UniformGroup +{ +public: + UMipmap1(GLuint _program) { + LocateUniform(uMinLod); + LocateUniform(uMaxTile); + } + + void update(bool _force) override + { + uMinLod.set(gDP.primColor.m, _force); + uMaxTile.set(gSP.texture.level, _force); + } + +private: + fUniform uMinLod; + iUniform uMaxTile; +}; + +class UMipmap2 : public UniformGroup +{ +public: + UMipmap2(GLuint _program) { + LocateUniform(uEnableLod); + LocateUniform(uTextureDetail); + } + + void update(bool _force) override + { + const int uCalcLOD = (gDP.otherMode.textureLOD == G_TL_LOD) ? 1 : 0; + uEnableLod.set(uCalcLOD, _force); + uTextureDetail.set(gDP.otherMode.textureDetail, _force); + } + +private: + iUniform uEnableLod; + iUniform uTextureDetail; +}; + +class UTextureSizeFast : public UniformGroup +{ +public: + UTextureSizeFast(GLuint _program, bool _useT0, bool _useT1) + : m_useT0(_useT0) + , m_useT1(_useT1) + { + LocateUniform(uTextureSize[0]); + LocateUniform(uTextureSize[1]); + } + + void update(bool _force) override + { + TextureCache & cache = textureCache(); + if (m_useT0 && cache.current[0] != NULL) + uTextureSize[0].set((float)cache.current[0]->width, (float)cache.current[0]->height, _force); + if (m_useT1 && cache.current[1] != NULL) + uTextureSize[1].set((float)cache.current[1]->width, (float)cache.current[1]->height, _force); + } + +private: + fv2Uniform uTextureSize[2]; + bool m_useT0; + bool m_useT1; +}; + +class UTextureParamsFast : public UniformGroup +{ +public: + UTextureParamsFast(GLuint _program, bool _useT0, bool _useT1) + { + m_useTile[0] = _useT0; + m_useTile[1] = _useT1; + LocateUniform(uTexOffset[0]); + LocateUniform(uTexOffset[1]); + LocateUniform(uCacheShiftScale[0]); + LocateUniform(uCacheShiftScale[1]); + LocateUniform(uCacheScale[0]); + LocateUniform(uCacheScale[1]); + LocateUniform(uCacheOffset[0]); + LocateUniform(uCacheOffset[1]); + LocateUniform(uTexScale); + LocateUniform(uCacheFrameBuffer); + } + + void update(bool _force) override + { + int nFB[2] = { 0, 0 }; + TextureCache & cache = textureCache(); + for (u32 t = 0; t < 2; ++t) { + if (!m_useTile[t]) + continue; + + gDPTile * pTile = gSP.textureTile[t]; + if (pTile != nullptr) { + if (pTile->textureMode == TEXTUREMODE_BGIMAGE || pTile->textureMode == TEXTUREMODE_FRAMEBUFFER_BG) + uTexOffset[t].set(0.0f, 0.0f, _force); + else { + float fuls = pTile->fuls; + float fult = pTile->fult; + if (pTile->frameBufferAddress > 0) { + FrameBuffer * pBuffer = frameBufferList().getBuffer(pTile->frameBufferAddress); + if (pBuffer != nullptr) { + if (pTile->masks > 0 && pTile->clamps == 0) + fuls = float(pTile->uls % (1 << pTile->masks)); + if (pTile->maskt > 0 && pTile->clampt == 0) + fult = float(pTile->ult % (1 << pTile->maskt)); + } else { + pTile->frameBufferAddress = 0; + } + } + uTexOffset[t].set(fuls, fult, _force); + } + } + + CachedTexture *_pTexture = cache.current[t]; + if (_pTexture != nullptr) { + f32 shiftScaleS = 1.0f; + f32 shiftScaleT = 1.0f; + getTextureShiftScale(t, cache, shiftScaleS, shiftScaleT); + uCacheShiftScale[t].set(shiftScaleS, shiftScaleT, _force); + uCacheScale[t].set(_pTexture->scaleS, _pTexture->scaleT, _force); + uCacheOffset[t].set(_pTexture->offsetS, _pTexture->offsetT, _force); + nFB[t] = _pTexture->frameBufferTexture; + } + } + + uCacheFrameBuffer.set(nFB[0], nFB[1], _force); + uTexScale.set(gSP.texture.scales, gSP.texture.scalet, _force); + } + +private: + bool m_useTile[2]; + fv2Uniform uTexOffset[2]; + fv2Uniform uCacheShiftScale[2]; + fv2Uniform uCacheScale[2]; + fv2Uniform uCacheOffset[2]; + fv2Uniform uTexScale; + iv2Uniform uCacheFrameBuffer; +}; + +class UClampWrapMirrorTex : public UniformGroup +{ +public: + UClampWrapMirrorTex(GLuint _program, bool _useT0, bool _useT1) + { + m_useTile[0] = _useT0; + m_useTile[1] = _useT1; + LocateUniform(uTexClamp0); + LocateUniform(uTexClamp1); + LocateUniform(uTexWrap0); + LocateUniform(uTexWrap1); + LocateUniform(uTexMirror0); + LocateUniform(uTexMirror1); + LocateUniform(uTexScale0); + LocateUniform(uTexScale1); + } + + void update(bool _force) override + { + std::array aTexClamp[2] = { { -10000.0f, -10000.0f, 10000.0f, 10000.0f }, + { -10000.0f, -10000.0f, 10000.0f, 10000.0f } }; + std::array aTexWrap[2] = { { 10000.0f, 10000.0f }, { 10000.0f, 10000.0f } }; + std::array aTexMirror[2] = { { 0.0f, 0.0f}, { 0.0f, 0.0f } }; + std::array aTexScale[2] = { { 1.0f, 1.0f },{ 1.0f, 1.0f } }; + TextureCache & cache = textureCache(); + const bool replaceTex1ByTex0 = needReplaceTex1ByTex0(); + for (u32 t = 0; t < 2; ++t) { + if (!m_useTile[t]) + continue; + + const u32 tile = replaceTex1ByTex0 ? 0 : t; + const gDPTile * pTile = gSP.textureTile[tile]; + CachedTexture * pTexture = cache.current[tile]; + if (pTile == nullptr || pTexture == nullptr) + continue; + + if (gDP.otherMode.cycleType != G_CYC_COPY) { + if (pTexture->clampS) { + aTexClamp[t][0] = 0.0f; // S lower bound + if (pTexture->frameBufferTexture != CachedTexture::fbNone || + pTile->textureMode == TEXTUREMODE_BGIMAGE) + aTexClamp[t][2] = 1.0f; + else { + u32 tileWidth = ((pTile->lrs - pTile->uls) & 0x03FF) + 1; + if (pTile->size > pTexture->size) + tileWidth <<= pTile->size - pTexture->size; + // aTexClamp[t][2] = f32(tileWidth) / (pTexture->mirrorS ? f32(pTexture->width) : f32(pTexture->clampWidth)); // S upper bound + aTexClamp[t][2] = f32(tileWidth) / f32(pTexture->width); // S upper bound + } + } + if (pTexture->clampT) { + aTexClamp[t][1] = 0.0f; // T lower bound + if (pTexture->frameBufferTexture != CachedTexture::fbNone || + pTile->textureMode == TEXTUREMODE_BGIMAGE) + aTexClamp[t][3] = 1.0f; + else { + const u32 tileHeight = ((pTile->lrt - pTile->ult) & 0x03FF) + 1; + // aTexClamp[t][3] = f32(tileHeight) / (pTexture->mirrorT ? f32(pTexture->height) : f32(pTexture->clampHeight)); // T upper bound + aTexClamp[t][3] = f32(tileHeight) / f32(pTexture->height); // T upper bound + } + } + } + if (pTexture->maskS) { + const f32 wrapWidth = static_cast(1 << pTile->originalMaskS); + const f32 pow2Width = static_cast(pow2(pTexture->width)); + aTexWrap[t][0] = wrapWidth / pow2Width; + aTexScale[t][0] = pow2Width / f32(pTexture->width); + } + if (pTexture->maskT) { + const f32 wrapHeight = static_cast(1 << pTile->originalMaskT); + const f32 pow2Height = static_cast(pow2(pTexture->height)); + aTexWrap[t][1] = wrapHeight / pow2Height; + aTexScale[t][1] = pow2Height / f32(pTexture->height); + } + if (pTexture->mirrorS) { + aTexMirror[t][0] = 1.0f; + aTexWrap[t][0] *= 2.0f; + } + if (pTexture->mirrorT) { + aTexMirror[t][1] = 1.0f; + aTexWrap[t][1] *= 2.0f; + } + } + + uTexClamp0.set(aTexClamp[0].data(), _force); + uTexClamp1.set(aTexClamp[1].data(), _force); + uTexWrap0.set(aTexWrap[0][0], aTexWrap[0][1], _force); + uTexWrap1.set(aTexWrap[1][0], aTexWrap[1][1], _force); + uTexMirror0.set(aTexMirror[0][0], aTexMirror[0][1], _force); + uTexMirror1.set(aTexMirror[1][0], aTexMirror[1][1], _force); + uTexScale0.set(aTexScale[0][0], aTexScale[0][1], _force); + uTexScale1.set(aTexScale[1][0], aTexScale[1][1], _force); + } + +private: + bool m_useTile[2]; + fv4Uniform uTexClamp0; + fv4Uniform uTexClamp1; + fv2Uniform uTexWrap0; + fv2Uniform uTexWrap1; + fv2Uniform uTexMirror0; + fv2Uniform uTexMirror1; + fv2Uniform uTexScale0; + fv2Uniform uTexScale1; +}; + +/*---------------CombinerProgramUniformFactoryCommon-------------*/ + +void CombinerProgramUniformFactoryFast::_addRasterInfo(GLuint _program, UniformGroups &_uniforms) const +{ + _uniforms.emplace_back(new URasterInfoFast(_program)); +} + +void CombinerProgramUniformFactoryFast::_addMipmap(GLuint _program, UniformGroups &_uniforms) const +{ + _uniforms.emplace_back(new UMipmap1(_program)); +} + +void CombinerProgramUniformFactoryFast::_addMipmap2(GLuint _program, UniformGroups &_uniforms) const +{ + _uniforms.emplace_back(new UMipmap2(_program)); +} + +void CombinerProgramUniformFactoryFast::_addTextureSize(GLuint _program, UniformGroups &_uniforms, bool _usesTile0, bool _usesTile1) const +{ + _uniforms.emplace_back(new UTextureSizeFast(_program, _usesTile0, _usesTile1)); +} + +void CombinerProgramUniformFactoryFast::_addTextureParams(GLuint _program, UniformGroups &_uniforms, bool _usesTile0, bool _usesTile1) const +{ + _uniforms.emplace_back(new UTextureParamsFast(_program, _usesTile0, _usesTile1)); +} + +void CombinerProgramUniformFactoryFast::_addClampWrapMirrorEngine(GLuint _program, UniformGroups &_uniforms, bool _usesTile0, bool _usesTile1) const +{ + _uniforms.emplace_back(new UClampWrapMirrorTex(_program, _usesTile0, _usesTile1)); +} + +CombinerProgramUniformFactoryFast::CombinerProgramUniformFactoryFast(const opengl::GLInfo & _glInfo) +: CombinerProgramUniformFactoryCommon(_glInfo) +{ +} + +} diff --git a/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactoryFast.h b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactoryFast.h new file mode 100644 index 00000000..9f004b7a --- /dev/null +++ b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactoryFast.h @@ -0,0 +1,26 @@ +#pragma once +#include +#include "glsl_CombinerProgramImpl.h" +#include "glsl_CombinerProgramUniformFactoryCommon.h" + +namespace glsl { +class CombinerProgramUniformFactoryFast : public CombinerProgramUniformFactoryCommon { + +public: + CombinerProgramUniformFactoryFast(const opengl::GLInfo & _glInfo); +private: + + virtual void _addRasterInfo(GLuint _program, UniformGroups &_uniforms) const override; + + virtual void _addMipmap(GLuint _program, UniformGroups &_uniforms) const override; + + virtual void _addMipmap2(GLuint _program, UniformGroups &_uniforms) const override; + + virtual void _addTextureSize(GLuint _program, UniformGroups &_uniforms, bool _usesTile0, bool _usesTile1) const override; + + virtual void _addTextureParams(GLuint _program, UniformGroups &_uniforms, bool _usesTile0, bool _usesTile1) const override; + + virtual void _addClampWrapMirrorEngine(GLuint _program, UniformGroups &_uniforms, bool _usesTile0, bool _usesTile1) const override; +}; +} + diff --git a/src/Graphics/OpenGLContext/GLSL/glsl_ShaderStorage.cpp b/src/Graphics/OpenGLContext/GLSL/glsl_ShaderStorage.cpp index 0a3304ff..0cf4c91e 100644 --- a/src/Graphics/OpenGLContext/GLSL/glsl_ShaderStorage.cpp +++ b/src/Graphics/OpenGLContext/GLSL/glsl_ShaderStorage.cpp @@ -14,10 +14,12 @@ #include #include #include +#include #include "glsl_Utils.h" #include "glsl_ShaderStorage.h" #include "glsl_CombinerProgramImpl.h" -#include "glsl_CombinerProgramUniformFactory.h" +#include "glsl_CombinerProgramUniformFactoryAccurate.h" +#include "glsl_CombinerProgramUniformFactoryFast.h" using namespace glsl; @@ -203,7 +205,7 @@ bool ShaderStorage::saveShadersStorage(const graphics::Combiners & _combiners) c static CombinerProgramImpl * _readCombinerProgramFromStream(std::istream & _is, CombinerKey& _cmbKey, - CombinerProgramUniformFactory & _uniformFactory, + std::unique_ptr & _uniformFactory, opengl::CachedUseProgram * _useProgram) { int inputs; @@ -226,7 +228,7 @@ CombinerProgramImpl * _readCombinerProgramFromStream(std::istream & _is, } UniformGroups uniforms; - _uniformFactory.buildUniforms(program, cmbInputs, _cmbKey, uniforms); + _uniformFactory->buildUniforms(program, cmbInputs, _cmbKey, uniforms); return new CombinerProgramImpl(_cmbKey, program, _useProgram, cmbInputs, std::move(uniforms)); } @@ -336,7 +338,14 @@ bool ShaderStorage::loadShadersStorage(graphics::Combiners & _combiners) return _loadFromCombinerKeys(_combiners); displayLoadProgress(L"LOAD COMBINER SHADERS %.1f%%", 0.0f); - CombinerProgramUniformFactory uniformFactory(m_glinfo); + + std::unique_ptr uniformFactory; + + if (config.generalEmulation.enableInaccurateTextureCoordinates) { + uniformFactory = std::make_unique(m_glinfo); + } else { + uniformFactory = std::make_unique(m_glinfo); + } fin.read((char*)&len, sizeof(len)); const f32 percent = len / 100.0f; diff --git a/src/Graphics/OpenGLContext/GLSL/glsl_ShaderStorage.h b/src/Graphics/OpenGLContext/GLSL/glsl_ShaderStorage.h index 0fce4232..fe5a5173 100644 --- a/src/Graphics/OpenGLContext/GLSL/glsl_ShaderStorage.h +++ b/src/Graphics/OpenGLContext/GLSL/glsl_ShaderStorage.h @@ -20,7 +20,7 @@ namespace glsl { bool _saveCombinerKeys(const graphics::Combiners & _combiners) const; bool _loadFromCombinerKeys(graphics::Combiners & _combiners); - const u32 m_formatVersion = 0x37U; + const u32 m_formatVersion = 0x38U; const u32 m_keysFormatVersion = 0x05; const opengl::GLInfo & m_glinfo; opengl::CachedUseProgram * m_useProgram; diff --git a/src/Graphics/OpenGLContext/opengl_ContextImpl.cpp b/src/Graphics/OpenGLContext/opengl_ContextImpl.cpp index 14f9e844..c02e2e52 100644 --- a/src/Graphics/OpenGLContext/opengl_ContextImpl.cpp +++ b/src/Graphics/OpenGLContext/opengl_ContextImpl.cpp @@ -13,7 +13,8 @@ #endif #include "opengl_ColorBufferReaderWithReadPixels.h" #include "opengl_Utils.h" -#include "GLSL/glsl_CombinerProgramBuilder.h" +#include "GLSL/glsl_CombinerProgramBuilderAccurate.h" +#include "GLSL/glsl_CombinerProgramBuilderFast.h" #include "GLSL/glsl_SpecialShadersFactory.h" #include "GLSL/glsl_ShaderStorage.h" @@ -408,7 +409,13 @@ void ContextImpl::resetCombinerProgramBuilder() { if (!isCombinerProgramBuilderObsolete()) return; - m_combinerProgramBuilder.reset(new glsl::CombinerProgramBuilder(m_glInfo, m_cachedFunctions->getCachedUseProgram())); + + if (config.generalEmulation.enableInaccurateTextureCoordinates) { + m_combinerProgramBuilder = std::make_unique(m_glInfo, m_cachedFunctions->getCachedUseProgram()); + } else { + m_combinerProgramBuilder = std::make_unique(m_glInfo, m_cachedFunctions->getCachedUseProgram()); + } + m_specialShadersFactory.reset(new glsl::SpecialShadersFactory(m_glInfo, m_cachedFunctions->getCachedUseProgram(), m_combinerProgramBuilder->getVertexShaderHeader(), diff --git a/src/GraphicsDrawer.cpp b/src/GraphicsDrawer.cpp index 2f5065e5..656fdb40 100644 --- a/src/GraphicsDrawer.cpp +++ b/src/GraphicsDrawer.cpp @@ -1277,15 +1277,59 @@ void GraphicsDrawer::drawTexturedRect(const TexturedRectParams & _params) for (u32 t = 0; t < 2; ++t) { if (pCurrentCombiner->usesTile(t) && cache.current[t] && gSP.textureTile[t]) { - const f32 uls = _FIXED2FLOAT(_params.s, 5); - const f32 lrs = uls + offsetX; - const f32 ult = _FIXED2FLOAT(_params.t, 5); - const f32 lrt = ult + offsetY; - texST[t].s0 = uls; - texST[t].s1 = lrs; - texST[t].t0 = ult; - texST[t].t1 = lrt; + if (config.generalEmulation.enableInaccurateTextureCoordinates) { + f32 shiftScaleS = 1.0f; + f32 shiftScaleT = 1.0f; + + s16 S = _params.s; + if (gSP.textureTile[t]->shifts > 10) { + const u32 shifts = 16 - gSP.textureTile[t]->shifts; + S = static_cast(S << shifts); + shiftScaleS = static_cast(1 << shifts); + } else if (gSP.textureTile[t]->shifts > 0) { + const u32 shifts = gSP.textureTile[t]->shifts; + S = static_cast(S >> shifts); + shiftScaleS /= static_cast(1 << shifts); + } + const f32 uls = _FIXED2FLOAT(S, 5); + const f32 lrs = uls + offsetX * shiftScaleS; + + s16 T = _params.t; + if (gSP.textureTile[t]->shiftt > 10) { + const u32 shiftt = 16 - gSP.textureTile[t]->shiftt; + T = static_cast(T << shiftt); + shiftScaleT = static_cast(1 << shiftt); + } else if (gSP.textureTile[t]->shiftt > 0) { + const u32 shiftt = gSP.textureTile[t]->shiftt; + T = static_cast(T >> shiftt); + shiftScaleT /= static_cast(1 << shiftt); + } + const f32 ult = _FIXED2FLOAT(T, 5); + const f32 lrt = ult + offsetY * shiftScaleT; + + texST[t].s0 = uls - gSP.textureTile[t]->fuls; + texST[t].s1 = lrs - gSP.textureTile[t]->fuls; + texST[t].t0 = ult - gSP.textureTile[t]->fult; + texST[t].t1 = lrt - gSP.textureTile[t]->fult; + + if (cache.current[t]->frameBufferTexture != CachedTexture::fbNone) { + texST[t].s0 = cache.current[t]->offsetS + texST[t].s0; + texST[t].t0 = cache.current[t]->offsetT + texST[t].t0; + texST[t].s1 = cache.current[t]->offsetS + texST[t].s1; + texST[t].t1 = cache.current[t]->offsetT + texST[t].t1; + } + } else { + const f32 uls = _FIXED2FLOAT(_params.s, 5); + const f32 lrs = uls + offsetX; + const f32 ult = _FIXED2FLOAT(_params.t, 5); + const f32 lrt = ult + offsetY; + + texST[t].s0 = uls; + texST[t].s1 = lrs; + texST[t].t0 = ult; + texST[t].t1 = lrt; + } if (cache.current[t]->frameBufferTexture != CachedTexture::fbMultiSample) { Context::TexParameters texParams; @@ -1310,6 +1354,13 @@ void GraphicsDrawer::drawTexturedRect(const TexturedRectParams & _params) gfxContext.setTextureParameters(texParams); } } + + if (config.generalEmulation.enableInaccurateTextureCoordinates) { + texST[t].s0 *= cache.current[t]->scaleS; + texST[t].t0 *= cache.current[t]->scaleT; + texST[t].s1 *= cache.current[t]->scaleS; + texST[t].t1 *= cache.current[t]->scaleT; + } } } diff --git a/src/Textures.cpp b/src/Textures.cpp index 4bf6a36c..b579f5ed 100644 --- a/src/Textures.cpp +++ b/src/Textures.cpp @@ -1100,7 +1100,206 @@ void doubleTexture(T* pTex, u32 width, u32 height) } } -void TextureCache::_load(u32 _tile, CachedTexture *_pTexture) +void TextureCache::_loadFast(u32 _tile, CachedTexture *_pTexture) +{ + u64 ricecrc = 0; + if (_loadHiresTexture(_tile, _pTexture, ricecrc)) + return; + + s32 mipLevel = 0; + bool force32bitFormat = false; + _pTexture->max_level = 0; + + if (config.generalEmulation.enableLOD != 0 && gSP.texture.level > 1) { + if (_tile == 0) { + _pTexture->max_level = 0; + } else { + _pTexture->max_level = static_cast(gSP.texture.level - 1); + const u16 dim = std::max(_pTexture->width, _pTexture->height); + while (dim < static_cast(1 << _pTexture->max_level)) + --_pTexture->max_level; + + auto texFormat = gDP.tiles[gSP.texture.tile + 1].format; + auto texSize = gDP.tiles[gSP.texture.tile + 1].size; + u32 tileMipLevel = gSP.texture.tile + 2; + while (!force32bitFormat && (tileMipLevel < gSP.texture.tile + gSP.texture.level)) { + gDPTile const& mipTile = gDP.tiles[tileMipLevel++]; + force32bitFormat = texFormat != mipTile.format || texSize != mipTile.size; + } + } + } + + u32 sizeShift = 1; + { + const TextureLoadParameters & loadParams = + ImageFormat::get().tlp[gDP.otherMode.textureLUT][_pTexture->size][_pTexture->format]; + if (force32bitFormat || loadParams.autoFormat == internalcolorFormat::RGBA8) + sizeShift = 2; + } + _pTexture->textureBytes = (_pTexture->width * _pTexture->height) << sizeShift; + + unsigned int totalTexSize = std::max(static_cast(_pTexture->textureBytes/sizeof(u32) + 8), MIPMAP_TILE_WIDTH) + * (_pTexture->max_level + 1); + + if (m_tempTextureHolder.size() < totalTexSize) { + m_tempTextureHolder.resize(totalTexSize); + } + + GetTexelFunc GetTexel; + InternalColorFormatParam glInternalFormat; + DatatypeParam glType; + + auto getLoadParams = [&](u16 _format, u16 _size) + { + const TextureLoadParameters & loadParams = + ImageFormat::get().tlp[gDP.otherMode.textureLUT][_size][_format]; + if (force32bitFormat || loadParams.autoFormat == internalcolorFormat::RGBA8) { + GetTexel = loadParams.Get32; + glInternalFormat = loadParams.glInternalFormat32; + glType = loadParams.glType32; + } + else { + GetTexel = loadParams.Get16; + glInternalFormat = loadParams.glInternalFormat16; + glType = loadParams.glType16; + } + }; + + CachedTexture tmptex = *_pTexture; + u16 line = tmptex.line; + + while (true) { + getLoadParams(tmptex.format, tmptex.size); + { + const u32 tileMipLevel = gSP.texture.tile + mipLevel + 1; + gDPTile & mipTile = gDP.tiles[tileMipLevel]; + if (tmptex.max_level > 1 && + tmptex.width == (mipTile.lrs - mipTile.uls + 1) * 2 && + tmptex.height == (mipTile.lrt - mipTile.ult + 1) * 2) + { + // Special case for Southern Swamp grass texture, Zelda MM. See #2315 + const u16 texWidth = tmptex.width; + const u16 texHeight = tmptex.height; + tmptex.width = mipTile.lrs - mipTile.uls + 1; + tmptex.height = mipTile.lrt - mipTile.ult + 1; + _getTextureDestData(tmptex, m_tempTextureHolder.data(), glInternalFormat, GetTexel, &line); + if (sizeShift == 2) + doubleTexture(m_tempTextureHolder.data(), tmptex.width, tmptex.height); + else + doubleTexture((u16*)m_tempTextureHolder.data(), tmptex.width, tmptex.height); + tmptex.width = texWidth; + tmptex.height = texHeight; + } else { + _getTextureDestData(tmptex, m_tempTextureHolder.data(), glInternalFormat, GetTexel, &line); + } + } + + if ((config.generalEmulation.hacks&hack_LoadDepthTextures) != 0 && gDP.colorImage.address == gDP.depthImageAddress) { + _loadDepthTexture(_pTexture, (u16*)m_tempTextureHolder.data()); + return; + } + + if (m_toggleDumpTex && + config.textureFilter.txHiresEnable != 0 && + config.hotkeys.enabledKeys[Config::HotKey::hkTexDump] != 0) { + txfilter_dmptx((u8*)m_tempTextureHolder.data(), tmptex.width, tmptex.height, + tmptex.width, (u16)u32(glInternalFormat), + (unsigned short)(_pTexture->format << 8 | _pTexture->size), + ricecrc); + } + + bool bLoaded = false; + bool needEnhance = (config.textureFilter.txEnhancementMode | config.textureFilter.txFilterMode) != 0 && + _pTexture->max_level == 0 && + TFH.isInited(); + if (needEnhance) { + if (config.textureFilter.txFilterIgnoreBG != 0) { + switch (GBI.getMicrocodeType()) { + case S2DEX_1_07: + case S2DEX_1_03: + case S2DEX_1_05: + needEnhance = RSP.cmd != 0x01 && RSP.cmd != 0x02; + break; + case S2DEX2: + needEnhance = RSP.cmd != 0x09 && RSP.cmd != 0x0A; + break; + } + } + } + + if (needEnhance) { + GHQTexInfo ghqTexInfo; + if (txfilter_filter((u8*)m_tempTextureHolder.data(), tmptex.width, tmptex.height, + (u16)u32(glInternalFormat), (uint64)_pTexture->crc, + &ghqTexInfo) != 0 && ghqTexInfo.data != nullptr) { + if (ghqTexInfo.width % 2 != 0 && + ghqTexInfo.format != u32(internalcolorFormat::RGBA8) && + m_curUnpackAlignment > 1) + gfxContext.setTextureUnpackAlignment(2); + ghqTexInfo.format = gfxContext.convertInternalTextureFormat(ghqTexInfo.format); + Context::InitTextureParams params; + params.handle = _pTexture->name; + params.textureUnitIndex = textureIndices::Tex[_tile]; + params.mipMapLevel = 0; + params.msaaLevel = 0; + params.width = ghqTexInfo.width; + params.height = ghqTexInfo.height; + params.internalFormat = InternalColorFormatParam(ghqTexInfo.format); + params.format = ColorFormatParam(ghqTexInfo.texture_format); + params.dataType = DatatypeParam(ghqTexInfo.pixel_type); + params.data = ghqTexInfo.data; + gfxContext.init2DTexture(params); + _updateCachedTexture(ghqTexInfo, _pTexture, tmptex.width, tmptex.height); + bLoaded = true; + } + } + if (!bLoaded) { + if (tmptex.width % 2 != 0 && + glInternalFormat != internalcolorFormat::RGBA8 && + m_curUnpackAlignment > 1) + gfxContext.setTextureUnpackAlignment(2); + Context::InitTextureParams params; + params.handle = _pTexture->name; + params.textureUnitIndex = textureIndices::Tex[_tile]; + params.mipMapLevel = mipLevel; + params.mipMapLevels = _pTexture->max_level + 1; + params.msaaLevel = 0; + params.width = tmptex.width; + params.height = tmptex.height; + params.internalFormat = gfxContext.convertInternalTextureFormat(u32(glInternalFormat)); + params.format = colorFormat::RGBA; + params.dataType = glType; + params.data = m_tempTextureHolder.data(); + gfxContext.init2DTexture(params); + } + if (mipLevel == _pTexture->max_level) + break; + ++mipLevel; + const u32 tileMipLevel = gSP.texture.tile + mipLevel + 1; + gDPTile & mipTile = gDP.tiles[tileMipLevel]; + line = mipTile.line; + tmptex.tMem = mipTile.tmem; + tmptex.palette = mipTile.palette; + tmptex.maskS = mipTile.masks; + tmptex.maskT = mipTile.maskt; + tmptex.format = mipTile.format; + tmptex.size = mipTile.size; + TileSizes sizes; + _calcTileSizes(tileMipLevel, sizes, nullptr); + tmptex.clampWidth = sizes.clampWidth; + tmptex.clampHeight = sizes.clampHeight; + // Insure mip-map levels size consistency. + if (tmptex.width > 1) + tmptex.width >>= 1; + if (tmptex.height > 1) + tmptex.height >>= 1; + _pTexture->textureBytes += (tmptex.width * tmptex.height) << sizeShift; + } + if (m_curUnpackAlignment > 1) + gfxContext.setTextureUnpackAlignment(m_curUnpackAlignment); +} + +void TextureCache::_loadAccurate(u32 _tile, CachedTexture *_pTexture) { u64 ricecrc = 0; if (_loadHiresTexture(_tile, _pTexture, ricecrc)) @@ -1125,28 +1324,12 @@ void TextureCache::_load(u32 _tile, CachedTexture *_pTexture) } _pTexture->textureBytes = (_pTexture->width * _pTexture->height) << sizeShift; - // RAII holder for texture data - class TexData - { - public: - TexData(u32 bytes) - { - pData = (u32*)malloc(bytes); - assert(pData != NULL); - } - ~TexData() - { - free(pData); - pData = NULL; - } - u32 * get() const - { - return pData; - } - private: - u32 *pData = NULL; - } texData(std::max((_pTexture->textureBytes + 8*sizeof(u32)), MIPMAP_TILE_WIDTH * sizeof(u32)) - * (_pTexture->max_level + 1)); + unsigned int totalTexSize = std::max(static_cast(_pTexture->textureBytes/sizeof(u32) + 8), MIPMAP_TILE_WIDTH) + * (_pTexture->max_level + 1); + + if (m_tempTextureHolder.size() < totalTexSize) { + m_tempTextureHolder.resize(totalTexSize); + } GetTexelFunc GetTexel; InternalColorFormatParam glInternalFormat; @@ -1180,15 +1363,15 @@ void TextureCache::_load(u32 _tile, CachedTexture *_pTexture) while (true) { const u32 tileSizePacked = texDataOffset | (tmptex.width << 16) | (tmptex.height << 24); - texData.get()[mipLevel] = tileSizePacked; + m_tempTextureHolder[mipLevel] = tileSizePacked; getLoadParams(tmptex.format, tmptex.size); - _getTextureDestData(tmptex, texData.get() + texDataOffset, glInternalFormat, GetTexel, &line); + _getTextureDestData(tmptex, &m_tempTextureHolder[texDataOffset], glInternalFormat, GetTexel, &line); if (m_toggleDumpTex && config.textureFilter.txHiresEnable != 0 && config.hotkeys.enabledKeys[Config::HotKey::hkTexDump] != 0) { - txfilter_dmptx((u8*)texData.get() + texDataOffset, tmptex.width, tmptex.height, + txfilter_dmptx((u8*)(m_tempTextureHolder.data() + texDataOffset), tmptex.width, tmptex.height, tmptex.width, (u16)u32(glInternalFormat), (unsigned short)(_pTexture->format << 8 | _pTexture->size), ricecrc); @@ -1228,7 +1411,7 @@ void TextureCache::_load(u32 _tile, CachedTexture *_pTexture) params.internalFormat = gfxContext.convertInternalTextureFormat(u32(glInternalFormat)); params.format = colorFormat::RGBA; params.dataType = glType; - params.data = texData.get(); + params.data = m_tempTextureHolder.data(); gfxContext.init2DTexture(params); _pTexture->mipmapAtlasWidth = params.width; _pTexture->mipmapAtlasHeight = params.height; @@ -1236,17 +1419,17 @@ void TextureCache::_load(u32 _tile, CachedTexture *_pTexture) else { getLoadParams(tmptex.format, tmptex.size); - _getTextureDestData(tmptex, texData.get(), glInternalFormat, GetTexel, &line); + _getTextureDestData(tmptex, m_tempTextureHolder.data(), glInternalFormat, GetTexel, &line); if ((config.generalEmulation.hacks&hack_LoadDepthTextures) != 0 && gDP.colorImage.address == gDP.depthImageAddress) { - _loadDepthTexture(_pTexture, (u16*)texData.get()); + _loadDepthTexture(_pTexture, (u16*)m_tempTextureHolder.data()); return; } if (m_toggleDumpTex && config.textureFilter.txHiresEnable != 0 && config.hotkeys.enabledKeys[Config::HotKey::hkTexDump] != 0) { - txfilter_dmptx((u8*)texData.get(), tmptex.width, tmptex.height, + txfilter_dmptx((u8*)m_tempTextureHolder.data(), tmptex.width, tmptex.height, tmptex.width, (u16)u32(glInternalFormat), (unsigned short)(_pTexture->format << 8 | _pTexture->size), ricecrc); @@ -1273,7 +1456,7 @@ void TextureCache::_load(u32 _tile, CachedTexture *_pTexture) if (needEnhance) { GHQTexInfo ghqTexInfo; - if (txfilter_filter((u8*)texData.get(), tmptex.width, tmptex.height, + if (txfilter_filter((u8*)m_tempTextureHolder.data(), tmptex.width, tmptex.height, (u16)u32(glInternalFormat), (uint64)_pTexture->crc, &ghqTexInfo) != 0 && ghqTexInfo.data != nullptr) { if (ghqTexInfo.width % 2 != 0 && @@ -1313,7 +1496,7 @@ void TextureCache::_load(u32 _tile, CachedTexture *_pTexture) params.internalFormat = gfxContext.convertInternalTextureFormat(u32(glInternalFormat)); params.format = colorFormat::RGBA; params.dataType = glType; - params.data = texData.get(); + params.data = m_tempTextureHolder.data(); gfxContext.init2DTexture(params); } } @@ -1565,6 +1748,14 @@ void TextureCache::update(u32 _t) return; } + if (_t == 1 && needReplaceTex1ByTex0()) { + current[1] = current[0]; + if (current[1] != nullptr) { + activateTexture(1, current[1]); + return; + } + } + if (gSP.texture.tile == 7 && _t == 0 && gSP.textureTile[0] == gDP.loadTile && @@ -1660,7 +1851,11 @@ void TextureCache::update(u32 _t) pCurrent->offsetS = 0.0f; pCurrent->offsetT = 0.0f; - _load(_t, pCurrent); + if (config.generalEmulation.enableInaccurateTextureCoordinates) { + _loadFast(_t, pCurrent); + } else { + _loadAccurate(_t, pCurrent); + } activateTexture( _t, pCurrent ); current[_t] = pCurrent; @@ -1686,4 +1881,11 @@ void getTextureShiftScale(u32 t, const TextureCache & cache, f32 & shiftScaleS, shiftScaleT = (f32)(1 << (16 - gSP.textureTile[t]->shiftt)); else if (gSP.textureTile[t]->shiftt > 0) shiftScaleT /= (f32)(1 << gSP.textureTile[t]->shiftt); -} \ No newline at end of file +} + +bool needReplaceTex1ByTex0() +{ + return config.generalEmulation.enableInaccurateTextureCoordinates && + gSP.texture.level == 0 && gDP.otherMode.textureLOD == G_TL_LOD && gDP.otherMode.textureDetail == G_TD_CLAMP; +} + diff --git a/src/Textures.h b/src/Textures.h index cc28ae71..eed20677 100644 --- a/src/Textures.h +++ b/src/Textures.h @@ -5,6 +5,7 @@ #include #include #include +#include #include // for size_t #include "CRC.h" @@ -84,7 +85,8 @@ private: void _checkCacheSize(); CachedTexture * _addTexture(u64 _crc64); - void _load(u32 _tile, CachedTexture *_pTexture); + void _loadFast(u32 _tile, CachedTexture *_pTexture); + void _loadAccurate(u32 _tile, CachedTexture *_pTexture); bool _loadHiresTexture(u32 _tile, CachedTexture *_pTexture, u64 & _ricecrc); void _loadBackground(CachedTexture *pTexture); bool _loadHiresBackground(CachedTexture *_pTexture, u64 & _ricecrc); @@ -104,6 +106,7 @@ private: u32 m_hits, m_misses; s32 m_curUnpackAlignment; bool m_toggleDumpTex; + std::vector m_tempTextureHolder; #ifdef VC const size_t m_maxCacheSize = 1500; #else @@ -113,6 +116,9 @@ private: void getTextureShiftScale(u32 tile, const TextureCache & cache, f32 & shiftScaleS, f32 & shiftScaleT); +// Check for situation when Tex0 is used instead of Tex1 +bool needReplaceTex1ByTex0(); + inline TextureCache & textureCache() { return TextureCache::get(); diff --git a/src/gDP.cpp b/src/gDP.cpp index abb1c055..b56abf06 100644 --- a/src/gDP.cpp +++ b/src/gDP.cpp @@ -858,7 +858,7 @@ void gDPTextureRectangle(f32 ulx, f32 uly, f32 lrx, f32 lry, s32 tile, s16 s, s1 textureTileOrg[0] = gSP.textureTile[0]; textureTileOrg[1] = gSP.textureTile[1]; gSP.textureTile[0] = &gDP.tiles[tile]; - gSP.textureTile[1] = &gDP.tiles[(tile + 1) & 7]; + gSP.textureTile[1] = needReplaceTex1ByTex0() ? &gDP.tiles[tile] : &gDP.tiles[(tile + 1) & 7]; // HACK ALERT! if (s == 0x4000 && (gDP.colorImage.width + gSP.textureTile[0]->uls < 512)) @@ -973,7 +973,7 @@ void LLETriangle::start(u32 _tile) m_textureScaleOrg[1] = gSP.texture.scalet; gSP.texture.tile = _tile; gSP.textureTile[0] = &gDP.tiles[_tile]; - gSP.textureTile[1] = &gDP.tiles[(_tile + 1) & 7]; + gSP.textureTile[1] = needReplaceTex1ByTex0() ? &gDP.tiles[_tile] : &gDP.tiles[(_tile + 1) & 7]; gSP.texture.scales = 1.0f; gSP.texture.scalet = 1.0f; m_flushed = false; diff --git a/src/mupenplus/Config_mupenplus.cpp b/src/mupenplus/Config_mupenplus.cpp index ff9ddc4e..e96d62da 100644 --- a/src/mupenplus/Config_mupenplus.cpp +++ b/src/mupenplus/Config_mupenplus.cpp @@ -163,6 +163,8 @@ bool Config_SetDefault() assert(res == M64ERR_SUCCESS); res = ConfigSetDefaultBool(g_configVideoGliden64, "EnableHybridFilter", config.generalEmulation.enableHybridFilter, "Enable hybrid integer scaling filter. Can be slow with low-end GPUs."); assert(res == M64ERR_SUCCESS); + res = ConfigSetDefaultBool(g_configVideoGliden64, "EnableInaccurateTextureCoordinates", config.generalEmulation.enableInaccurateTextureCoordinates, "Use fast but less accurate shaders. Can help with low-end GPUs."); + assert(res == M64ERR_SUCCESS); res = ConfigSetDefaultBool(g_configVideoGliden64, "EnableFragmentDepthWrite", config.generalEmulation.enableFragmentDepthWrite, "Enable writing of fragment depth. Some mobile GPUs do not support it, thus made optional. Leave enabled."); assert(res == M64ERR_SUCCESS); res = ConfigSetDefaultBool(g_configVideoGliden64, "EnableCustomSettings", config.generalEmulation.enableCustomSettings, "Use GLideN64 per-game settings."); @@ -508,6 +510,7 @@ void Config_LoadConfig() config.generalEmulation.enableShadersStorage = ConfigGetParamBool(g_configVideoGliden64, "EnableShadersStorage"); config.generalEmulation.enableLegacyBlending = ConfigGetParamBool(g_configVideoGliden64, "EnableLegacyBlending"); config.generalEmulation.enableHybridFilter = ConfigGetParamBool(g_configVideoGliden64, "EnableHybridFilter"); + config.generalEmulation.enableInaccurateTextureCoordinates = ConfigGetParamBool(g_configVideoGliden64, "EnableInaccurateTextureCoordinates"); config.generalEmulation.enableFragmentDepthWrite = ConfigGetParamBool(g_configVideoGliden64, "EnableFragmentDepthWrite"); config.generalEmulation.enableCustomSettings = ConfigGetParamBool(g_configVideoGliden64, "EnableCustomSettings"); #if defined(OS_ANDROID) || defined(OS_IOS)