From 7374a023eff964817c9e5fbe75a661540516f798 Mon Sep 17 00:00:00 2001 From: UjinT34 <41110182+UjinT34@users.noreply.github.com> Date: Sat, 29 Mar 2025 03:19:35 +0300 Subject: [PATCH] renderer/opengl: Extract shaders from source (#9600) --------- Co-authored-by: Mihai Fufezan --- .gitignore | 2 + CMakeLists.txt | 6 +- meson.build | 4 +- scripts/generateShaderIncludes.sh | 24 + src/debug/HyprCtl.cpp | 9 + src/render/OpenGL.cpp | 864 +++++++++++------- src/render/OpenGL.hpp | 46 +- src/render/Shader.cpp | 12 - src/render/Shader.hpp | 3 +- src/render/Shaders.hpp | 5 - src/render/shaders/SharedValues.hpp | 3 - src/render/shaders/Textures.hpp | 541 ----------- src/render/shaders/glsl/CM.frag | 55 ++ src/render/shaders/{CM.frag => glsl/CM.glsl} | 120 +-- src/render/shaders/glsl/blur1.frag | 141 +++ src/render/shaders/glsl/blur2.frag | 23 + src/render/shaders/glsl/blurfinish.frag | 32 + .../shaders/glsl/blurfinish_legacy.frag | 28 + src/render/shaders/glsl/blurprepare.frag | 58 ++ .../shaders/glsl/blurprepare_legacy.frag | 29 + src/render/shaders/glsl/border.frag | 183 ++++ .../{Border.hpp => glsl/border_legacy.frag} | 21 +- src/render/shaders/glsl/ext.frag | 35 + src/render/shaders/glsl/glitch.frag | 64 ++ src/render/shaders/glsl/passthru.frag | 7 + src/render/shaders/glsl/quad.frag | 14 + src/render/shaders/glsl/rgba.frag | 36 + src/render/shaders/glsl/rgbamatte.frag | 8 + src/render/shaders/glsl/rgbx.frag | 33 + src/render/shaders/glsl/rounding.glsl | 29 + src/render/shaders/glsl/shadow.frag | 100 ++ .../{Shadow.hpp => glsl/shadow_legacy.frag} | 8 +- src/render/shaders/glsl/tex.vert | 15 + src/render/shaders/glsl/tex300.vert | 17 + src/render/shaders/glsl/tex320.vert | 17 + 35 files changed, 1533 insertions(+), 1059 deletions(-) create mode 100755 scripts/generateShaderIncludes.sh delete mode 100644 src/render/Shaders.hpp delete mode 100644 src/render/shaders/SharedValues.hpp delete mode 100644 src/render/shaders/Textures.hpp create mode 100644 src/render/shaders/glsl/CM.frag rename src/render/shaders/{CM.frag => glsl/CM.glsl} (79%) create mode 100644 src/render/shaders/glsl/blur1.frag create mode 100644 src/render/shaders/glsl/blur2.frag create mode 100644 src/render/shaders/glsl/blurfinish.frag create mode 100644 src/render/shaders/glsl/blurfinish_legacy.frag create mode 100644 src/render/shaders/glsl/blurprepare.frag create mode 100644 src/render/shaders/glsl/blurprepare_legacy.frag create mode 100644 src/render/shaders/glsl/border.frag rename src/render/shaders/{Border.hpp => glsl/border_legacy.frag} (92%) create mode 100644 src/render/shaders/glsl/ext.frag create mode 100644 src/render/shaders/glsl/glitch.frag create mode 100644 src/render/shaders/glsl/passthru.frag create mode 100644 src/render/shaders/glsl/quad.frag create mode 100644 src/render/shaders/glsl/rgba.frag create mode 100644 src/render/shaders/glsl/rgbamatte.frag create mode 100644 src/render/shaders/glsl/rgbx.frag create mode 100644 src/render/shaders/glsl/rounding.glsl create mode 100644 src/render/shaders/glsl/shadow.frag rename src/render/shaders/{Shadow.hpp => glsl/shadow_legacy.frag} (96%) create mode 100644 src/render/shaders/glsl/tex.vert create mode 100644 src/render/shaders/glsl/tex300.vert create mode 100644 src/render/shaders/glsl/tex320.vert diff --git a/.gitignore b/.gitignore index a79347907..4ced16785 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,8 @@ protocols/*.c* protocols/*.h* .ccls-cache *.so +src/render/shaders/*.inc +src/render/shaders/Shaders.hpp hyprctl/hyprctl diff --git a/CMakeLists.txt b/CMakeLists.txt index c4ad4ca0d..b4c361585 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,9 @@ message(STATUS "Gathering git info") # Get git info hash and branch execute_process(COMMAND ./scripts/generateVersion.sh WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) +# Make shader files includable +execute_process(COMMAND ./scripts/generateShaderIncludes.sh + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) find_package(PkgConfig REQUIRED) @@ -445,4 +448,5 @@ install( DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland FILES_MATCHING PATTERN "*.h*" - PATTERN "*.frag") + PATTERN "*.inc" + ) diff --git a/meson.build b/meson.build index d9635a27f..a40975aa9 100644 --- a/meson.build +++ b/meson.build @@ -87,9 +87,11 @@ endif # Generate hyprland version and populate version.h run_command('sh', '-c', 'scripts/generateVersion.sh', check: true) +# Make shader files includable +run_command('sh', '-c', 'scripts/generateShaderIncludes.sh', check: true) # Install headers -globber = run_command('find', 'src', '-name', '*.h*', '-o', '-name', '*.frag', check: true) +globber = run_command('find', 'src', '-name', '*.h*', '-o', '-name', '*.inc', check: true) headers = globber.stdout().strip().split('\n') foreach file : headers install_headers(file, subdir: 'hyprland', preserve_path: true) diff --git a/scripts/generateShaderIncludes.sh b/scripts/generateShaderIncludes.sh new file mode 100755 index 000000000..20c78e9d9 --- /dev/null +++ b/scripts/generateShaderIncludes.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +SHADERS_SRC="./src/render/shaders/glsl" + +echo "-- Generating shader includes" + +if [ ! -d ./src/render/shaders ]; then + mkdir ./src/render/shaders +fi + +echo '#pragma once' > ./src/render/shaders/Shaders.hpp +echo '#include ' >> ./src/render/shaders/Shaders.hpp +echo 'static const std::map SHADERS = {' >> ./src/render/shaders/Shaders.hpp + +for filename in `ls ${SHADERS_SRC}`; do + echo "-- ${filename}" + + { echo 'R"#('; cat ${SHADERS_SRC}/${filename}; echo ')#"'; } > ./src/render/shaders/${filename}.inc + echo "{\"${filename}\"," >> ./src/render/shaders/Shaders.hpp + echo "#include \"./${filename}.inc\"" >> ./src/render/shaders/Shaders.hpp + echo "}," >> ./src/render/shaders/Shaders.hpp +done + +echo '};' >> ./src/render/shaders/Shaders.hpp diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 3f955f6ce..23385be81 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -51,6 +51,7 @@ using namespace Hyprutils::OS; #include "../managers/AnimationManager.hpp" #include "../debug/HyprNotificationOverlay.hpp" #include "../render/Renderer.hpp" +#include "../render/OpenGL.hpp" static void trimTrailingComma(std::string& str) { if (!str.empty() && str.back() == ',') @@ -1643,6 +1644,13 @@ static std::string submapRequest(eHyprCtlOutputFormat format, std::string reques return format == FORMAT_JSON ? std::format("{{\"{}\"}}\n", escapeJSONStrings(submap)) : (submap + "\n"); } +static std::string reloadShaders(eHyprCtlOutputFormat format, std::string request) { + if (g_pHyprOpenGL->initShaders()) + return format == FORMAT_JSON ? "{\"ok\": true}" : "ok"; + else + return format == FORMAT_JSON ? "{\"ok\": false}" : "error"; +} + CHyprCtl::CHyprCtl() { registerCommand(SHyprCtlCommand{"workspaces", true, workspacesRequest}); registerCommand(SHyprCtlCommand{"workspacerules", true, workspaceRulesRequest}); @@ -1665,6 +1673,7 @@ CHyprCtl::CHyprCtl() { registerCommand(SHyprCtlCommand{"locked", true, getIsLocked}); registerCommand(SHyprCtlCommand{"descriptions", true, getDescriptions}); registerCommand(SHyprCtlCommand{"submap", true, submapRequest}); + registerCommand(SHyprCtlCommand{.name = "reloadshaders", .exact = true, .fn = reloadShaders}); registerCommand(SHyprCtlCommand{"monitors", false, monitorsRequest}); registerCommand(SHyprCtlCommand{"reload", false, reloadRequest}); diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 675955ee1..2c455ba05 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -1,6 +1,7 @@ +#include +#include #include #include -#include "Shaders.hpp" #include "OpenGL.hpp" #include "Renderer.hpp" #include "../Compositor.hpp" @@ -10,16 +11,24 @@ #include "../protocols/LayerShell.hpp" #include "../protocols/core/Compositor.hpp" #include "../protocols/ColorManagement.hpp" +#include "../protocols/types/ColorManagement.hpp" #include "../managers/HookSystemManager.hpp" #include "../managers/input/InputManager.hpp" +#include "../helpers/fs/FsUtils.hpp" +#include "debug/HyprNotificationOverlay.hpp" +#include "hyprerror/HyprError.hpp" #include "pass/TexPassElement.hpp" #include "pass/RectPassElement.hpp" #include "pass/PreBlurElement.hpp" #include "pass/ClearPassElement.hpp" +#include "render/Shader.hpp" +#include #include #include #include #include +#include "./shaders/Shaders.hpp" + using namespace Hyprutils::OS; using namespace NColorManagement; @@ -688,7 +697,7 @@ void CHyprOpenGLImpl::beginSimple(PHLMONITOR pMonitor, const CRegion& damage, SP m_RenderData.pCurrentMonData = &m_mMonitorRenderResources[pMonitor]; - if (!m_RenderData.pCurrentMonData->m_bShadersInitialized) + if (!m_bShadersInitialized) initShaders(); m_RenderData.damage.set(damage); @@ -737,7 +746,7 @@ void CHyprOpenGLImpl::begin(PHLMONITOR pMonitor, const CRegion& damage_, CFrameb m_RenderData.pCurrentMonData = &m_mMonitorRenderResources[pMonitor]; - if (!m_RenderData.pCurrentMonData->m_bShadersInitialized) + if (!m_bShadersInitialized) initShaders(); // ensure a framebuffer for the monitor exists @@ -859,217 +868,326 @@ void CHyprOpenGLImpl::setDamage(const CRegion& damage_, std::optional f m_RenderData.finalDamage.set(finalDamage.value_or(damage_)); } -void CHyprOpenGLImpl::initShaders() { - GLuint prog = createProgram(QUADVERTSRC, QUADFRAGSRC); - m_RenderData.pCurrentMonData->m_shQUAD.program = prog; - m_RenderData.pCurrentMonData->m_shQUAD.proj = glGetUniformLocation(prog, "proj"); - m_RenderData.pCurrentMonData->m_shQUAD.color = glGetUniformLocation(prog, "color"); - m_RenderData.pCurrentMonData->m_shQUAD.posAttrib = glGetAttribLocation(prog, "pos"); - m_RenderData.pCurrentMonData->m_shQUAD.topLeft = glGetUniformLocation(prog, "topLeft"); - m_RenderData.pCurrentMonData->m_shQUAD.fullSize = glGetUniformLocation(prog, "fullSize"); - m_RenderData.pCurrentMonData->m_shQUAD.radius = glGetUniformLocation(prog, "radius"); - m_RenderData.pCurrentMonData->m_shQUAD.roundingPower = glGetUniformLocation(prog, "roundingPower"); - -#ifndef GLES2 - if (m_eglContextVersion == EGL_CONTEXT_GLES_3_2 /* GLES2 and GLES3.0 can't compile the CM shader */) { - prog = createProgram(TEXVERTSRC320, TEXFRAGSRCCM, true, true); - m_bCMSupported = prog > 0; - if (m_bCMSupported) { - m_RenderData.pCurrentMonData->m_shCM.program = prog; - m_RenderData.pCurrentMonData->m_shCM.proj = glGetUniformLocation(prog, "proj"); - m_RenderData.pCurrentMonData->m_shCM.tex = glGetUniformLocation(prog, "tex"); - m_RenderData.pCurrentMonData->m_shCM.texType = glGetUniformLocation(prog, "texType"); - m_RenderData.pCurrentMonData->m_shCM.sourceTF = glGetUniformLocation(prog, "sourceTF"); - m_RenderData.pCurrentMonData->m_shCM.targetTF = glGetUniformLocation(prog, "targetTF"); - m_RenderData.pCurrentMonData->m_shCM.sourcePrimaries = glGetUniformLocation(prog, "sourcePrimaries"); - m_RenderData.pCurrentMonData->m_shCM.targetPrimaries = glGetUniformLocation(prog, "targetPrimaries"); - m_RenderData.pCurrentMonData->m_shCM.maxLuminance = glGetUniformLocation(prog, "maxLuminance"); - m_RenderData.pCurrentMonData->m_shCM.dstMaxLuminance = glGetUniformLocation(prog, "dstMaxLuminance"); - m_RenderData.pCurrentMonData->m_shCM.dstRefLuminance = glGetUniformLocation(prog, "dstRefLuminance"); - m_RenderData.pCurrentMonData->m_shCM.sdrSaturation = glGetUniformLocation(prog, "sdrSaturation"); - m_RenderData.pCurrentMonData->m_shCM.sdrBrightness = glGetUniformLocation(prog, "sdrBrightnessMultiplier"); - m_RenderData.pCurrentMonData->m_shCM.alphaMatte = glGetUniformLocation(prog, "texMatte"); - m_RenderData.pCurrentMonData->m_shCM.alpha = glGetUniformLocation(prog, "alpha"); - m_RenderData.pCurrentMonData->m_shCM.texAttrib = glGetAttribLocation(prog, "texcoord"); - m_RenderData.pCurrentMonData->m_shCM.matteTexAttrib = glGetAttribLocation(prog, "texcoordMatte"); - m_RenderData.pCurrentMonData->m_shCM.posAttrib = glGetAttribLocation(prog, "pos"); - m_RenderData.pCurrentMonData->m_shCM.discardOpaque = glGetUniformLocation(prog, "discardOpaque"); - m_RenderData.pCurrentMonData->m_shCM.discardAlpha = glGetUniformLocation(prog, "discardAlpha"); - m_RenderData.pCurrentMonData->m_shCM.discardAlphaValue = glGetUniformLocation(prog, "discardAlphaValue"); - m_RenderData.pCurrentMonData->m_shCM.topLeft = glGetUniformLocation(prog, "topLeft"); - m_RenderData.pCurrentMonData->m_shCM.fullSize = glGetUniformLocation(prog, "fullSize"); - m_RenderData.pCurrentMonData->m_shCM.radius = glGetUniformLocation(prog, "radius"); - m_RenderData.pCurrentMonData->m_shCM.roundingPower = glGetUniformLocation(prog, "roundingPower"); - m_RenderData.pCurrentMonData->m_shCM.applyTint = glGetUniformLocation(prog, "applyTint"); - m_RenderData.pCurrentMonData->m_shCM.tint = glGetUniformLocation(prog, "tint"); - m_RenderData.pCurrentMonData->m_shCM.useAlphaMatte = glGetUniformLocation(prog, "useAlphaMatte"); - } else { - Debug::log( - ERR, - "WARNING: CM Shader failed compiling, color management will not work. It's likely because your GPU is an old piece of garbage, don't file bug reports about this!"); - } +// TODO notify user if bundled shader is newer than ~/.config override +static std::string loadShader(const std::string& filename) { + const auto home = Hyprutils::Path::getHome(); + if (home.has_value()) { + const auto src = NFsUtils::readFileAsString(home.value() + "/hypr/shaders/" + filename); + if (src.has_value()) + return src.value(); } + for (auto& e : ASSET_PATHS) { + const auto src = NFsUtils::readFileAsString(std::string{e} + "/hypr/shaders/" + filename); + if (src.has_value()) + return src.value(); + } + if (SHADERS.contains(filename)) + return SHADERS.at(filename); + throw std::runtime_error(std::format("Couldn't load shader {}", filename)); +} + +static void loadShaderInclude(const std::string& filename, std::map& includes) { + includes.insert({filename, loadShader(filename)}); +} + +static void processShaderIncludes(std::string& source, const std::map& includes) { + for (auto it = includes.begin(); it != includes.end(); ++it) { + Hyprutils::String::replaceInString(source, "#include \"" + it->first + "\"", it->second); + } +} + +static std::string processShader(const std::string& filename, const std::map& includes) { + auto source = loadShader(filename); + processShaderIncludes(source, includes); + return source; +} + +// shader has #include "CM.glsl" +static void getCMShaderUniforms(CShader& shader) { + shader.skipCM = glGetUniformLocation(shader.program, "skipCM"); + shader.sourceTF = glGetUniformLocation(shader.program, "sourceTF"); + shader.targetTF = glGetUniformLocation(shader.program, "targetTF"); + shader.sourcePrimaries = glGetUniformLocation(shader.program, "sourcePrimaries"); + shader.targetPrimaries = glGetUniformLocation(shader.program, "targetPrimaries"); + shader.maxLuminance = glGetUniformLocation(shader.program, "maxLuminance"); + shader.dstMaxLuminance = glGetUniformLocation(shader.program, "dstMaxLuminance"); + shader.dstRefLuminance = glGetUniformLocation(shader.program, "dstRefLuminance"); + shader.sdrSaturation = glGetUniformLocation(shader.program, "sdrSaturation"); + shader.sdrBrightness = glGetUniformLocation(shader.program, "sdrBrightnessMultiplier"); +} + +// shader has #include "rounding.glsl" +static void getRoundingShaderUniforms(CShader& shader) { + shader.topLeft = glGetUniformLocation(shader.program, "topLeft"); + shader.fullSize = glGetUniformLocation(shader.program, "fullSize"); + shader.radius = glGetUniformLocation(shader.program, "radius"); + shader.roundingPower = glGetUniformLocation(shader.program, "roundingPower"); +} + +bool CHyprOpenGLImpl::initShaders() { + auto shaders = makeShared(); + const bool isDynamic = m_bShadersInitialized; + static const auto PCM = CConfigValue("render:cm_enabled"); + + try { + std::map includes; + loadShaderInclude("rounding.glsl", includes); + loadShaderInclude("CM.glsl", includes); + + shaders->TEXVERTSRC = processShader("tex.vert", includes); + shaders->TEXVERTSRC300 = processShader("tex300.vert", includes); + shaders->TEXVERTSRC320 = processShader("tex320.vert", includes); + + GLuint prog; +#ifdef GLES2 + m_bCMSupported = false; +#else + if (!*PCM) + m_bCMSupported = false; + else { + const auto TEXFRAGSRCCM = processShader("CM.frag", includes); + + prog = createProgram(shaders->TEXVERTSRC300, TEXFRAGSRCCM, true, true); + if (m_bShadersInitialized && m_bCMSupported && prog == 0) + g_pHyprNotificationOverlay->addNotification("CM shader reload failed, falling back to rgba/rgbx", CHyprColor{}, 15000, ICON_WARNING); + + m_bCMSupported = prog > 0; + if (m_bCMSupported) { + shaders->m_shCM.program = prog; + getCMShaderUniforms(shaders->m_shCM); + getRoundingShaderUniforms(shaders->m_shCM); + shaders->m_shCM.proj = glGetUniformLocation(prog, "proj"); + shaders->m_shCM.tex = glGetUniformLocation(prog, "tex"); + shaders->m_shCM.texType = glGetUniformLocation(prog, "texType"); + shaders->m_shCM.alphaMatte = glGetUniformLocation(prog, "texMatte"); + shaders->m_shCM.alpha = glGetUniformLocation(prog, "alpha"); + shaders->m_shCM.texAttrib = glGetAttribLocation(prog, "texcoord"); + shaders->m_shCM.matteTexAttrib = glGetAttribLocation(prog, "texcoordMatte"); + shaders->m_shCM.posAttrib = glGetAttribLocation(prog, "pos"); + shaders->m_shCM.discardOpaque = glGetUniformLocation(prog, "discardOpaque"); + shaders->m_shCM.discardAlpha = glGetUniformLocation(prog, "discardAlpha"); + shaders->m_shCM.discardAlphaValue = glGetUniformLocation(prog, "discardAlphaValue"); + shaders->m_shCM.applyTint = glGetUniformLocation(prog, "applyTint"); + shaders->m_shCM.tint = glGetUniformLocation(prog, "tint"); + shaders->m_shCM.useAlphaMatte = glGetUniformLocation(prog, "useAlphaMatte"); + } else + Debug::log(ERR, + "WARNING: CM Shader failed compiling, color management will not work. It's likely because your GPU is an old piece of garbage, don't file bug reports " + "about this!"); + } #endif - prog = createProgram(TEXVERTSRC, TEXFRAGSRCRGBA); - m_RenderData.pCurrentMonData->m_shRGBA.program = prog; - m_RenderData.pCurrentMonData->m_shRGBA.proj = glGetUniformLocation(prog, "proj"); - m_RenderData.pCurrentMonData->m_shRGBA.tex = glGetUniformLocation(prog, "tex"); - m_RenderData.pCurrentMonData->m_shRGBA.alphaMatte = glGetUniformLocation(prog, "texMatte"); - m_RenderData.pCurrentMonData->m_shRGBA.alpha = glGetUniformLocation(prog, "alpha"); - m_RenderData.pCurrentMonData->m_shRGBA.texAttrib = glGetAttribLocation(prog, "texcoord"); - m_RenderData.pCurrentMonData->m_shRGBA.matteTexAttrib = glGetAttribLocation(prog, "texcoordMatte"); - m_RenderData.pCurrentMonData->m_shRGBA.posAttrib = glGetAttribLocation(prog, "pos"); - m_RenderData.pCurrentMonData->m_shRGBA.discardOpaque = glGetUniformLocation(prog, "discardOpaque"); - m_RenderData.pCurrentMonData->m_shRGBA.discardAlpha = glGetUniformLocation(prog, "discardAlpha"); - m_RenderData.pCurrentMonData->m_shRGBA.discardAlphaValue = glGetUniformLocation(prog, "discardAlphaValue"); - m_RenderData.pCurrentMonData->m_shRGBA.topLeft = glGetUniformLocation(prog, "topLeft"); - m_RenderData.pCurrentMonData->m_shRGBA.fullSize = glGetUniformLocation(prog, "fullSize"); - m_RenderData.pCurrentMonData->m_shRGBA.radius = glGetUniformLocation(prog, "radius"); - m_RenderData.pCurrentMonData->m_shRGBA.roundingPower = glGetUniformLocation(prog, "roundingPower"); - m_RenderData.pCurrentMonData->m_shRGBA.applyTint = glGetUniformLocation(prog, "applyTint"); - m_RenderData.pCurrentMonData->m_shRGBA.tint = glGetUniformLocation(prog, "tint"); - m_RenderData.pCurrentMonData->m_shRGBA.useAlphaMatte = glGetUniformLocation(prog, "useAlphaMatte"); + const auto FRAGSHADOW = processShader(m_bCMSupported ? "shadow.frag" : "shadow_legacy.frag", includes); + const auto FRAGBORDER1 = processShader(m_bCMSupported ? "border.frag" : "border_legacy.frag", includes); + const auto FRAGBLURPREPARE = processShader(m_bCMSupported ? "blurprepare.frag" : "blurprepare_legacy.frag", includes); + const auto FRAGBLURFINISH = processShader(m_bCMSupported ? "blurfinish.frag" : "blurfinish_legacy.frag", includes); + const auto QUADFRAGSRC = processShader("quad.frag", includes); + const auto TEXFRAGSRCRGBA = processShader("rgba.frag", includes); + const auto TEXFRAGSRCRGBAPASSTHRU = processShader("passthru.frag", includes); + const auto TEXFRAGSRCRGBAMATTE = processShader("rgbamatte.frag", includes); + const auto FRAGGLITCH = processShader("glitch.frag", includes); + const auto TEXFRAGSRCRGBX = processShader("rgbx.frag", includes); + const auto TEXFRAGSRCEXT = processShader("ext.frag", includes); + const auto FRAGBLUR1 = processShader("blur1.frag", includes); + const auto FRAGBLUR2 = processShader("blur2.frag", includes); - prog = createProgram(TEXVERTSRC, TEXFRAGSRCRGBAPASSTHRU); - m_RenderData.pCurrentMonData->m_shPASSTHRURGBA.program = prog; - m_RenderData.pCurrentMonData->m_shPASSTHRURGBA.proj = glGetUniformLocation(prog, "proj"); - m_RenderData.pCurrentMonData->m_shPASSTHRURGBA.tex = glGetUniformLocation(prog, "tex"); - m_RenderData.pCurrentMonData->m_shPASSTHRURGBA.texAttrib = glGetAttribLocation(prog, "texcoord"); - m_RenderData.pCurrentMonData->m_shPASSTHRURGBA.posAttrib = glGetAttribLocation(prog, "pos"); + prog = createProgram(shaders->TEXVERTSRC, QUADFRAGSRC, isDynamic); + if (!prog) + return false; + shaders->m_shQUAD.program = prog; + getRoundingShaderUniforms(shaders->m_shQUAD); + shaders->m_shQUAD.proj = glGetUniformLocation(prog, "proj"); + shaders->m_shQUAD.color = glGetUniformLocation(prog, "color"); + shaders->m_shQUAD.posAttrib = glGetAttribLocation(prog, "pos"); - prog = createProgram(TEXVERTSRC, TEXFRAGSRCRGBAMATTE); - m_RenderData.pCurrentMonData->m_shMATTE.program = prog; - m_RenderData.pCurrentMonData->m_shMATTE.proj = glGetUniformLocation(prog, "proj"); - m_RenderData.pCurrentMonData->m_shMATTE.tex = glGetUniformLocation(prog, "tex"); - m_RenderData.pCurrentMonData->m_shMATTE.alphaMatte = glGetUniformLocation(prog, "texMatte"); - m_RenderData.pCurrentMonData->m_shMATTE.texAttrib = glGetAttribLocation(prog, "texcoord"); - m_RenderData.pCurrentMonData->m_shMATTE.posAttrib = glGetAttribLocation(prog, "pos"); + prog = createProgram(shaders->TEXVERTSRC, TEXFRAGSRCRGBA, isDynamic); + if (!prog) + return false; + shaders->m_shRGBA.program = prog; + getRoundingShaderUniforms(shaders->m_shRGBA); + shaders->m_shRGBA.proj = glGetUniformLocation(prog, "proj"); + shaders->m_shRGBA.tex = glGetUniformLocation(prog, "tex"); + shaders->m_shRGBA.alphaMatte = glGetUniformLocation(prog, "texMatte"); + shaders->m_shRGBA.alpha = glGetUniformLocation(prog, "alpha"); + shaders->m_shRGBA.texAttrib = glGetAttribLocation(prog, "texcoord"); + shaders->m_shRGBA.matteTexAttrib = glGetAttribLocation(prog, "texcoordMatte"); + shaders->m_shRGBA.posAttrib = glGetAttribLocation(prog, "pos"); + shaders->m_shRGBA.discardOpaque = glGetUniformLocation(prog, "discardOpaque"); + shaders->m_shRGBA.discardAlpha = glGetUniformLocation(prog, "discardAlpha"); + shaders->m_shRGBA.discardAlphaValue = glGetUniformLocation(prog, "discardAlphaValue"); + shaders->m_shRGBA.applyTint = glGetUniformLocation(prog, "applyTint"); + shaders->m_shRGBA.tint = glGetUniformLocation(prog, "tint"); + shaders->m_shRGBA.useAlphaMatte = glGetUniformLocation(prog, "useAlphaMatte"); - prog = createProgram(TEXVERTSRC, FRAGGLITCH); - m_RenderData.pCurrentMonData->m_shGLITCH.program = prog; - m_RenderData.pCurrentMonData->m_shGLITCH.proj = glGetUniformLocation(prog, "proj"); - m_RenderData.pCurrentMonData->m_shGLITCH.tex = glGetUniformLocation(prog, "tex"); - m_RenderData.pCurrentMonData->m_shGLITCH.texAttrib = glGetAttribLocation(prog, "texcoord"); - m_RenderData.pCurrentMonData->m_shGLITCH.posAttrib = glGetAttribLocation(prog, "pos"); - m_RenderData.pCurrentMonData->m_shGLITCH.distort = glGetUniformLocation(prog, "distort"); - m_RenderData.pCurrentMonData->m_shGLITCH.time = glGetUniformLocation(prog, "time"); - m_RenderData.pCurrentMonData->m_shGLITCH.fullSize = glGetUniformLocation(prog, "screenSize"); + prog = createProgram(shaders->TEXVERTSRC, TEXFRAGSRCRGBAPASSTHRU, isDynamic); + if (!prog) + return false; + shaders->m_shPASSTHRURGBA.program = prog; + shaders->m_shPASSTHRURGBA.proj = glGetUniformLocation(prog, "proj"); + shaders->m_shPASSTHRURGBA.tex = glGetUniformLocation(prog, "tex"); + shaders->m_shPASSTHRURGBA.texAttrib = glGetAttribLocation(prog, "texcoord"); + shaders->m_shPASSTHRURGBA.posAttrib = glGetAttribLocation(prog, "pos"); - prog = createProgram(TEXVERTSRC, TEXFRAGSRCRGBX); - m_RenderData.pCurrentMonData->m_shRGBX.program = prog; - m_RenderData.pCurrentMonData->m_shRGBX.tex = glGetUniformLocation(prog, "tex"); - m_RenderData.pCurrentMonData->m_shRGBX.proj = glGetUniformLocation(prog, "proj"); - m_RenderData.pCurrentMonData->m_shRGBX.alpha = glGetUniformLocation(prog, "alpha"); - m_RenderData.pCurrentMonData->m_shRGBX.texAttrib = glGetAttribLocation(prog, "texcoord"); - m_RenderData.pCurrentMonData->m_shRGBX.posAttrib = glGetAttribLocation(prog, "pos"); - m_RenderData.pCurrentMonData->m_shRGBX.discardOpaque = glGetUniformLocation(prog, "discardOpaque"); - m_RenderData.pCurrentMonData->m_shRGBX.discardAlpha = glGetUniformLocation(prog, "discardAlpha"); - m_RenderData.pCurrentMonData->m_shRGBX.discardAlphaValue = glGetUniformLocation(prog, "discardAlphaValue"); - m_RenderData.pCurrentMonData->m_shRGBX.topLeft = glGetUniformLocation(prog, "topLeft"); - m_RenderData.pCurrentMonData->m_shRGBX.fullSize = glGetUniformLocation(prog, "fullSize"); - m_RenderData.pCurrentMonData->m_shRGBX.radius = glGetUniformLocation(prog, "radius"); - m_RenderData.pCurrentMonData->m_shRGBX.roundingPower = glGetUniformLocation(prog, "roundingPower"); - m_RenderData.pCurrentMonData->m_shRGBX.applyTint = glGetUniformLocation(prog, "applyTint"); - m_RenderData.pCurrentMonData->m_shRGBX.tint = glGetUniformLocation(prog, "tint"); + prog = createProgram(shaders->TEXVERTSRC, TEXFRAGSRCRGBAMATTE, isDynamic); + if (!prog) + return false; + shaders->m_shMATTE.program = prog; + shaders->m_shMATTE.proj = glGetUniformLocation(prog, "proj"); + shaders->m_shMATTE.tex = glGetUniformLocation(prog, "tex"); + shaders->m_shMATTE.alphaMatte = glGetUniformLocation(prog, "texMatte"); + shaders->m_shMATTE.texAttrib = glGetAttribLocation(prog, "texcoord"); + shaders->m_shMATTE.posAttrib = glGetAttribLocation(prog, "pos"); - prog = createProgram(TEXVERTSRC, TEXFRAGSRCEXT); - m_RenderData.pCurrentMonData->m_shEXT.program = prog; - m_RenderData.pCurrentMonData->m_shEXT.tex = glGetUniformLocation(prog, "tex"); - m_RenderData.pCurrentMonData->m_shEXT.proj = glGetUniformLocation(prog, "proj"); - m_RenderData.pCurrentMonData->m_shEXT.alpha = glGetUniformLocation(prog, "alpha"); - m_RenderData.pCurrentMonData->m_shEXT.posAttrib = glGetAttribLocation(prog, "pos"); - m_RenderData.pCurrentMonData->m_shEXT.texAttrib = glGetAttribLocation(prog, "texcoord"); - m_RenderData.pCurrentMonData->m_shEXT.discardOpaque = glGetUniformLocation(prog, "discardOpaque"); - m_RenderData.pCurrentMonData->m_shEXT.discardAlpha = glGetUniformLocation(prog, "discardAlpha"); - m_RenderData.pCurrentMonData->m_shEXT.discardAlphaValue = glGetUniformLocation(prog, "discardAlphaValue"); - m_RenderData.pCurrentMonData->m_shEXT.topLeft = glGetUniformLocation(prog, "topLeft"); - m_RenderData.pCurrentMonData->m_shEXT.fullSize = glGetUniformLocation(prog, "fullSize"); - m_RenderData.pCurrentMonData->m_shEXT.radius = glGetUniformLocation(prog, "radius"); - m_RenderData.pCurrentMonData->m_shEXT.roundingPower = glGetUniformLocation(prog, "roundingPower"); - m_RenderData.pCurrentMonData->m_shEXT.applyTint = glGetUniformLocation(prog, "applyTint"); - m_RenderData.pCurrentMonData->m_shEXT.tint = glGetUniformLocation(prog, "tint"); + prog = createProgram(shaders->TEXVERTSRC, FRAGGLITCH, isDynamic); + if (!prog) + return false; + shaders->m_shGLITCH.program = prog; + shaders->m_shGLITCH.proj = glGetUniformLocation(prog, "proj"); + shaders->m_shGLITCH.tex = glGetUniformLocation(prog, "tex"); + shaders->m_shGLITCH.texAttrib = glGetAttribLocation(prog, "texcoord"); + shaders->m_shGLITCH.posAttrib = glGetAttribLocation(prog, "pos"); + shaders->m_shGLITCH.distort = glGetUniformLocation(prog, "distort"); + shaders->m_shGLITCH.time = glGetUniformLocation(prog, "time"); + shaders->m_shGLITCH.fullSize = glGetUniformLocation(prog, "screenSize"); - prog = createProgram(TEXVERTSRC, FRAGBLUR1); - m_RenderData.pCurrentMonData->m_shBLUR1.program = prog; - m_RenderData.pCurrentMonData->m_shBLUR1.tex = glGetUniformLocation(prog, "tex"); - m_RenderData.pCurrentMonData->m_shBLUR1.alpha = glGetUniformLocation(prog, "alpha"); - m_RenderData.pCurrentMonData->m_shBLUR1.proj = glGetUniformLocation(prog, "proj"); - m_RenderData.pCurrentMonData->m_shBLUR1.posAttrib = glGetAttribLocation(prog, "pos"); - m_RenderData.pCurrentMonData->m_shBLUR1.texAttrib = glGetAttribLocation(prog, "texcoord"); - m_RenderData.pCurrentMonData->m_shBLUR1.radius = glGetUniformLocation(prog, "radius"); - m_RenderData.pCurrentMonData->m_shBLUR1.halfpixel = glGetUniformLocation(prog, "halfpixel"); - m_RenderData.pCurrentMonData->m_shBLUR1.passes = glGetUniformLocation(prog, "passes"); - m_RenderData.pCurrentMonData->m_shBLUR1.vibrancy = glGetUniformLocation(prog, "vibrancy"); - m_RenderData.pCurrentMonData->m_shBLUR1.vibrancy_darkness = glGetUniformLocation(prog, "vibrancy_darkness"); + prog = createProgram(shaders->TEXVERTSRC, TEXFRAGSRCRGBX, isDynamic); + if (!prog) + return false; + shaders->m_shRGBX.program = prog; + getRoundingShaderUniforms(shaders->m_shRGBX); + shaders->m_shRGBX.tex = glGetUniformLocation(prog, "tex"); + shaders->m_shRGBX.proj = glGetUniformLocation(prog, "proj"); + shaders->m_shRGBX.alpha = glGetUniformLocation(prog, "alpha"); + shaders->m_shRGBX.texAttrib = glGetAttribLocation(prog, "texcoord"); + shaders->m_shRGBX.posAttrib = glGetAttribLocation(prog, "pos"); + shaders->m_shRGBX.discardOpaque = glGetUniformLocation(prog, "discardOpaque"); + shaders->m_shRGBX.discardAlpha = glGetUniformLocation(prog, "discardAlpha"); + shaders->m_shRGBX.discardAlphaValue = glGetUniformLocation(prog, "discardAlphaValue"); + shaders->m_shRGBX.applyTint = glGetUniformLocation(prog, "applyTint"); + shaders->m_shRGBX.tint = glGetUniformLocation(prog, "tint"); - prog = createProgram(TEXVERTSRC, FRAGBLUR2); - m_RenderData.pCurrentMonData->m_shBLUR2.program = prog; - m_RenderData.pCurrentMonData->m_shBLUR2.tex = glGetUniformLocation(prog, "tex"); - m_RenderData.pCurrentMonData->m_shBLUR2.alpha = glGetUniformLocation(prog, "alpha"); - m_RenderData.pCurrentMonData->m_shBLUR2.proj = glGetUniformLocation(prog, "proj"); - m_RenderData.pCurrentMonData->m_shBLUR2.posAttrib = glGetAttribLocation(prog, "pos"); - m_RenderData.pCurrentMonData->m_shBLUR2.texAttrib = glGetAttribLocation(prog, "texcoord"); - m_RenderData.pCurrentMonData->m_shBLUR2.radius = glGetUniformLocation(prog, "radius"); - m_RenderData.pCurrentMonData->m_shBLUR2.halfpixel = glGetUniformLocation(prog, "halfpixel"); + prog = createProgram(shaders->TEXVERTSRC, TEXFRAGSRCEXT, isDynamic); + if (!prog) + return false; + shaders->m_shEXT.program = prog; + getRoundingShaderUniforms(shaders->m_shEXT); + shaders->m_shEXT.tex = glGetUniformLocation(prog, "tex"); + shaders->m_shEXT.proj = glGetUniformLocation(prog, "proj"); + shaders->m_shEXT.alpha = glGetUniformLocation(prog, "alpha"); + shaders->m_shEXT.posAttrib = glGetAttribLocation(prog, "pos"); + shaders->m_shEXT.texAttrib = glGetAttribLocation(prog, "texcoord"); + shaders->m_shEXT.discardOpaque = glGetUniformLocation(prog, "discardOpaque"); + shaders->m_shEXT.discardAlpha = glGetUniformLocation(prog, "discardAlpha"); + shaders->m_shEXT.discardAlphaValue = glGetUniformLocation(prog, "discardAlphaValue"); + shaders->m_shEXT.applyTint = glGetUniformLocation(prog, "applyTint"); + shaders->m_shEXT.tint = glGetUniformLocation(prog, "tint"); - prog = createProgram(TEXVERTSRC, FRAGBLURPREPARE); - m_RenderData.pCurrentMonData->m_shBLURPREPARE.program = prog; - m_RenderData.pCurrentMonData->m_shBLURPREPARE.tex = glGetUniformLocation(prog, "tex"); - m_RenderData.pCurrentMonData->m_shBLURPREPARE.proj = glGetUniformLocation(prog, "proj"); - m_RenderData.pCurrentMonData->m_shBLURPREPARE.posAttrib = glGetAttribLocation(prog, "pos"); - m_RenderData.pCurrentMonData->m_shBLURPREPARE.texAttrib = glGetAttribLocation(prog, "texcoord"); - m_RenderData.pCurrentMonData->m_shBLURPREPARE.contrast = glGetUniformLocation(prog, "contrast"); - m_RenderData.pCurrentMonData->m_shBLURPREPARE.brightness = glGetUniformLocation(prog, "brightness"); + prog = createProgram(shaders->TEXVERTSRC, FRAGBLUR1, isDynamic); + if (!prog) + return false; + shaders->m_shBLUR1.program = prog; + shaders->m_shBLUR1.tex = glGetUniformLocation(prog, "tex"); + shaders->m_shBLUR1.alpha = glGetUniformLocation(prog, "alpha"); + shaders->m_shBLUR1.proj = glGetUniformLocation(prog, "proj"); + shaders->m_shBLUR1.posAttrib = glGetAttribLocation(prog, "pos"); + shaders->m_shBLUR1.texAttrib = glGetAttribLocation(prog, "texcoord"); + shaders->m_shBLUR1.radius = glGetUniformLocation(prog, "radius"); + shaders->m_shBLUR1.halfpixel = glGetUniformLocation(prog, "halfpixel"); + shaders->m_shBLUR1.passes = glGetUniformLocation(prog, "passes"); + shaders->m_shBLUR1.vibrancy = glGetUniformLocation(prog, "vibrancy"); + shaders->m_shBLUR1.vibrancy_darkness = glGetUniformLocation(prog, "vibrancy_darkness"); - prog = createProgram(TEXVERTSRC, FRAGBLURFINISH); - m_RenderData.pCurrentMonData->m_shBLURFINISH.program = prog; - m_RenderData.pCurrentMonData->m_shBLURFINISH.tex = glGetUniformLocation(prog, "tex"); - m_RenderData.pCurrentMonData->m_shBLURFINISH.proj = glGetUniformLocation(prog, "proj"); - m_RenderData.pCurrentMonData->m_shBLURFINISH.posAttrib = glGetAttribLocation(prog, "pos"); - m_RenderData.pCurrentMonData->m_shBLURFINISH.texAttrib = glGetAttribLocation(prog, "texcoord"); - m_RenderData.pCurrentMonData->m_shBLURFINISH.brightness = glGetUniformLocation(prog, "brightness"); - m_RenderData.pCurrentMonData->m_shBLURFINISH.noise = glGetUniformLocation(prog, "noise"); + prog = createProgram(shaders->TEXVERTSRC, FRAGBLUR2, isDynamic); + if (!prog) + return false; + shaders->m_shBLUR2.program = prog; + shaders->m_shBLUR2.tex = glGetUniformLocation(prog, "tex"); + shaders->m_shBLUR2.alpha = glGetUniformLocation(prog, "alpha"); + shaders->m_shBLUR2.proj = glGetUniformLocation(prog, "proj"); + shaders->m_shBLUR2.posAttrib = glGetAttribLocation(prog, "pos"); + shaders->m_shBLUR2.texAttrib = glGetAttribLocation(prog, "texcoord"); + shaders->m_shBLUR2.radius = glGetUniformLocation(prog, "radius"); + shaders->m_shBLUR2.halfpixel = glGetUniformLocation(prog, "halfpixel"); - prog = createProgram(QUADVERTSRC, FRAGSHADOW); - m_RenderData.pCurrentMonData->m_shSHADOW.program = prog; - m_RenderData.pCurrentMonData->m_shSHADOW.proj = glGetUniformLocation(prog, "proj"); - m_RenderData.pCurrentMonData->m_shSHADOW.posAttrib = glGetAttribLocation(prog, "pos"); - m_RenderData.pCurrentMonData->m_shSHADOW.texAttrib = glGetAttribLocation(prog, "texcoord"); - m_RenderData.pCurrentMonData->m_shSHADOW.topLeft = glGetUniformLocation(prog, "topLeft"); - m_RenderData.pCurrentMonData->m_shSHADOW.bottomRight = glGetUniformLocation(prog, "bottomRight"); - m_RenderData.pCurrentMonData->m_shSHADOW.fullSize = glGetUniformLocation(prog, "fullSize"); - m_RenderData.pCurrentMonData->m_shSHADOW.radius = glGetUniformLocation(prog, "radius"); - m_RenderData.pCurrentMonData->m_shSHADOW.roundingPower = glGetUniformLocation(prog, "roundingPower"); - m_RenderData.pCurrentMonData->m_shSHADOW.range = glGetUniformLocation(prog, "range"); - m_RenderData.pCurrentMonData->m_shSHADOW.shadowPower = glGetUniformLocation(prog, "shadowPower"); - m_RenderData.pCurrentMonData->m_shSHADOW.color = glGetUniformLocation(prog, "color"); + prog = createProgram(m_bCMSupported ? shaders->TEXVERTSRC300 : shaders->TEXVERTSRC, FRAGBLURPREPARE, isDynamic); + if (!prog) + return false; + shaders->m_shBLURPREPARE.program = prog; + if (m_bCMSupported) + getCMShaderUniforms(shaders->m_shBLURPREPARE); - prog = createProgram(QUADVERTSRC, FRAGBORDER1); - m_RenderData.pCurrentMonData->m_shBORDER1.program = prog; - m_RenderData.pCurrentMonData->m_shBORDER1.proj = glGetUniformLocation(prog, "proj"); - m_RenderData.pCurrentMonData->m_shBORDER1.thick = glGetUniformLocation(prog, "thick"); - m_RenderData.pCurrentMonData->m_shBORDER1.posAttrib = glGetAttribLocation(prog, "pos"); - m_RenderData.pCurrentMonData->m_shBORDER1.texAttrib = glGetAttribLocation(prog, "texcoord"); - m_RenderData.pCurrentMonData->m_shBORDER1.topLeft = glGetUniformLocation(prog, "topLeft"); - m_RenderData.pCurrentMonData->m_shBORDER1.bottomRight = glGetUniformLocation(prog, "bottomRight"); - m_RenderData.pCurrentMonData->m_shBORDER1.fullSize = glGetUniformLocation(prog, "fullSize"); - m_RenderData.pCurrentMonData->m_shBORDER1.fullSizeUntransformed = glGetUniformLocation(prog, "fullSizeUntransformed"); - m_RenderData.pCurrentMonData->m_shBORDER1.radius = glGetUniformLocation(prog, "radius"); - m_RenderData.pCurrentMonData->m_shBORDER1.radiusOuter = glGetUniformLocation(prog, "radiusOuter"); - m_RenderData.pCurrentMonData->m_shBORDER1.roundingPower = glGetUniformLocation(prog, "roundingPower"); - m_RenderData.pCurrentMonData->m_shBORDER1.gradient = glGetUniformLocation(prog, "gradient"); - m_RenderData.pCurrentMonData->m_shBORDER1.gradient2 = glGetUniformLocation(prog, "gradient2"); - m_RenderData.pCurrentMonData->m_shBORDER1.gradientLength = glGetUniformLocation(prog, "gradientLength"); - m_RenderData.pCurrentMonData->m_shBORDER1.gradient2Length = glGetUniformLocation(prog, "gradient2Length"); - m_RenderData.pCurrentMonData->m_shBORDER1.angle = glGetUniformLocation(prog, "angle"); - m_RenderData.pCurrentMonData->m_shBORDER1.angle2 = glGetUniformLocation(prog, "angle2"); - m_RenderData.pCurrentMonData->m_shBORDER1.gradientLerp = glGetUniformLocation(prog, "gradientLerp"); - m_RenderData.pCurrentMonData->m_shBORDER1.alpha = glGetUniformLocation(prog, "alpha"); + shaders->m_shBLURPREPARE.tex = glGetUniformLocation(prog, "tex"); + shaders->m_shBLURPREPARE.proj = glGetUniformLocation(prog, "proj"); + shaders->m_shBLURPREPARE.posAttrib = glGetAttribLocation(prog, "pos"); + shaders->m_shBLURPREPARE.texAttrib = glGetAttribLocation(prog, "texcoord"); + shaders->m_shBLURPREPARE.contrast = glGetUniformLocation(prog, "contrast"); + shaders->m_shBLURPREPARE.brightness = glGetUniformLocation(prog, "brightness"); - m_RenderData.pCurrentMonData->m_bShadersInitialized = true; + prog = createProgram(m_bCMSupported ? shaders->TEXVERTSRC300 : shaders->TEXVERTSRC, FRAGBLURFINISH, isDynamic); + if (!prog) + return false; + shaders->m_shBLURFINISH.program = prog; + // getCMShaderUniforms(shaders->m_shBLURFINISH); + + shaders->m_shBLURFINISH.tex = glGetUniformLocation(prog, "tex"); + shaders->m_shBLURFINISH.proj = glGetUniformLocation(prog, "proj"); + shaders->m_shBLURFINISH.posAttrib = glGetAttribLocation(prog, "pos"); + shaders->m_shBLURFINISH.texAttrib = glGetAttribLocation(prog, "texcoord"); + shaders->m_shBLURFINISH.brightness = glGetUniformLocation(prog, "brightness"); + shaders->m_shBLURFINISH.noise = glGetUniformLocation(prog, "noise"); + + prog = createProgram(m_bCMSupported ? shaders->TEXVERTSRC300 : shaders->TEXVERTSRC, FRAGSHADOW, isDynamic); + if (!prog) + return false; + if (m_bCMSupported) + shaders->m_shSHADOW.program = prog; + getCMShaderUniforms(shaders->m_shSHADOW); + getRoundingShaderUniforms(shaders->m_shSHADOW); + shaders->m_shSHADOW.proj = glGetUniformLocation(prog, "proj"); + shaders->m_shSHADOW.posAttrib = glGetAttribLocation(prog, "pos"); + shaders->m_shSHADOW.texAttrib = glGetAttribLocation(prog, "texcoord"); + shaders->m_shSHADOW.bottomRight = glGetUniformLocation(prog, "bottomRight"); + shaders->m_shSHADOW.range = glGetUniformLocation(prog, "range"); + shaders->m_shSHADOW.shadowPower = glGetUniformLocation(prog, "shadowPower"); + shaders->m_shSHADOW.color = glGetUniformLocation(prog, "color"); + + prog = createProgram(m_bCMSupported ? shaders->TEXVERTSRC300 : shaders->TEXVERTSRC, FRAGBORDER1, isDynamic); + if (!prog) + return false; + shaders->m_shBORDER1.program = prog; + if (m_bCMSupported) + getCMShaderUniforms(shaders->m_shBORDER1); + + getRoundingShaderUniforms(shaders->m_shBORDER1); + shaders->m_shBORDER1.proj = glGetUniformLocation(prog, "proj"); + shaders->m_shBORDER1.thick = glGetUniformLocation(prog, "thick"); + shaders->m_shBORDER1.posAttrib = glGetAttribLocation(prog, "pos"); + shaders->m_shBORDER1.texAttrib = glGetAttribLocation(prog, "texcoord"); + shaders->m_shBORDER1.bottomRight = glGetUniformLocation(prog, "bottomRight"); + shaders->m_shBORDER1.fullSizeUntransformed = glGetUniformLocation(prog, "fullSizeUntransformed"); + shaders->m_shBORDER1.radiusOuter = glGetUniformLocation(prog, "radiusOuter"); + shaders->m_shBORDER1.gradient = glGetUniformLocation(prog, "gradient"); + shaders->m_shBORDER1.gradient2 = glGetUniformLocation(prog, "gradient2"); + shaders->m_shBORDER1.gradientLength = glGetUniformLocation(prog, "gradientLength"); + shaders->m_shBORDER1.gradient2Length = glGetUniformLocation(prog, "gradient2Length"); + shaders->m_shBORDER1.angle = glGetUniformLocation(prog, "angle"); + shaders->m_shBORDER1.angle2 = glGetUniformLocation(prog, "angle2"); + shaders->m_shBORDER1.gradientLerp = glGetUniformLocation(prog, "gradientLerp"); + shaders->m_shBORDER1.alpha = glGetUniformLocation(prog, "alpha"); + } catch (const std::exception& e) { + if (!m_bShadersInitialized) + throw e; + + Debug::log(ERR, "Shaders update failed: {}", e.what()); + return false; + } + + m_shaders = shaders; + m_bShadersInitialized = true; Debug::log(LOG, "Shaders initialized successfully."); + g_pHyprError->destroy(); + return true; } void CHyprOpenGLImpl::applyScreenShader(const std::string& path) { @@ -1090,7 +1208,15 @@ void CHyprOpenGLImpl::applyScreenShader(const std::string& path) { std::string fragmentShader((std::istreambuf_iterator(infile)), (std::istreambuf_iterator())); - m_sFinalScreenShader.program = createProgram(fragmentShader.starts_with("#version 320 es") ? TEXVERTSRC320 : TEXVERTSRC, fragmentShader, true); + m_sFinalScreenShader.program = createProgram( // + fragmentShader.starts_with("#version 320 es") // do not break existing custom shaders + ? + m_shaders->TEXVERTSRC320 : + (fragmentShader.starts_with("#version 300 es") // support lower es versions + ? + m_shaders->TEXVERTSRC300 : + m_shaders->TEXVERTSRC), + fragmentShader, true); if (!m_sFinalScreenShader.program) { // Error will have been sent by now by the underlying cause @@ -1242,17 +1368,17 @@ void CHyprOpenGLImpl::renderRectWithDamage(const CBox& box, const CHyprColor& co newBox, wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot); Mat3x3 glMatrix = m_RenderData.projection.copy().multiply(matrix); - glUseProgram(m_RenderData.pCurrentMonData->m_shQUAD.program); + glUseProgram(m_shaders->m_shQUAD.program); #ifndef GLES2 - glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shQUAD.proj, 1, GL_TRUE, glMatrix.getMatrix().data()); + glUniformMatrix3fv(m_shaders->m_shQUAD.proj, 1, GL_TRUE, glMatrix.getMatrix().data()); #else glMatrix.transpose(); glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shQUAD.proj, 1, GL_FALSE, glMatrix.getMatrix().data()); #endif // premultiply the color as well as we don't work with straight alpha - glUniform4f(m_RenderData.pCurrentMonData->m_shQUAD.color, col.r * col.a, col.g * col.a, col.b * col.a, col.a); + glUniform4f(m_shaders->m_shQUAD.color, col.r * col.a, col.g * col.a, col.b * col.a, col.a); CBox transformedBox = box; transformedBox.transform(wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x, @@ -1262,14 +1388,14 @@ void CHyprOpenGLImpl::renderRectWithDamage(const CBox& box, const CHyprColor& co const auto FULLSIZE = Vector2D(transformedBox.width, transformedBox.height); // Rounded corners - glUniform2f(m_RenderData.pCurrentMonData->m_shQUAD.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y); - glUniform2f(m_RenderData.pCurrentMonData->m_shQUAD.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y); - glUniform1f(m_RenderData.pCurrentMonData->m_shQUAD.radius, round); - glUniform1f(m_RenderData.pCurrentMonData->m_shQUAD.roundingPower, roundingPower); + glUniform2f(m_shaders->m_shQUAD.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y); + glUniform2f(m_shaders->m_shQUAD.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y); + glUniform1f(m_shaders->m_shQUAD.radius, round); + glUniform1f(m_shaders->m_shQUAD.roundingPower, roundingPower); - glVertexAttribPointer(m_RenderData.pCurrentMonData->m_shQUAD.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); + glVertexAttribPointer(m_shaders->m_shQUAD.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); - glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shQUAD.posAttrib); + glEnableVertexAttribArray(m_shaders->m_shQUAD.posAttrib); if (m_RenderData.clipBox.width != 0 && m_RenderData.clipBox.height != 0) { CRegion damageClip{m_RenderData.clipBox.x, m_RenderData.clipBox.y, m_RenderData.clipBox.width, m_RenderData.clipBox.height}; @@ -1288,7 +1414,7 @@ void CHyprOpenGLImpl::renderRectWithDamage(const CBox& box, const CHyprColor& co } } - glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shQUAD.posAttrib); + glDisableVertexAttribArray(m_shaders->m_shQUAD.posAttrib); scissor(nullptr); } @@ -1310,6 +1436,45 @@ void CHyprOpenGLImpl::renderTextureWithDamage(SP tex, const CBox& box, scissor(nullptr); } +void CHyprOpenGLImpl::passCMUniforms(const CShader& shader, const NColorManagement::SImageDescription& imageDescription, + const NColorManagement::SImageDescription& targetImageDescription, bool modifySDR) { + glUniform1i(shader.sourceTF, imageDescription.transferFunction); + glUniform1i(shader.targetTF, targetImageDescription.transferFunction); + const auto sourcePrimaries = + imageDescription.primariesNameSet || imageDescription.primaries == SPCPRimaries{} ? getPrimaries(imageDescription.primariesNamed) : imageDescription.primaries; + const auto targetPrimaries = targetImageDescription.primariesNameSet || targetImageDescription.primaries == SPCPRimaries{} ? + getPrimaries(targetImageDescription.primariesNamed) : + targetImageDescription.primaries; + + const GLfloat glSourcePrimaries[8] = { + sourcePrimaries.red.x, sourcePrimaries.red.y, sourcePrimaries.green.x, sourcePrimaries.green.y, + sourcePrimaries.blue.x, sourcePrimaries.blue.y, sourcePrimaries.white.x, sourcePrimaries.white.y, + }; + const GLfloat glTargetPrimaries[8] = { + targetPrimaries.red.x, targetPrimaries.red.y, targetPrimaries.green.x, targetPrimaries.green.y, + targetPrimaries.blue.x, targetPrimaries.blue.y, targetPrimaries.white.x, targetPrimaries.white.y, + }; + glUniformMatrix4x2fv(shader.sourcePrimaries, 1, false, glSourcePrimaries); + glUniformMatrix4x2fv(shader.targetPrimaries, 1, false, glTargetPrimaries); + + const float maxLuminance = imageDescription.luminances.max > 0 ? imageDescription.luminances.max : imageDescription.luminances.reference; + glUniform1f(shader.maxLuminance, maxLuminance * targetImageDescription.luminances.reference / imageDescription.luminances.reference); + glUniform1f(shader.dstMaxLuminance, targetImageDescription.luminances.max > 0 ? targetImageDescription.luminances.max : 10000); + glUniform1f(shader.dstRefLuminance, targetImageDescription.luminances.reference); + glUniform1f(shader.sdrSaturation, + modifySDR && m_RenderData.pMonitor->sdrSaturation > 0 && targetImageDescription.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ ? + m_RenderData.pMonitor->sdrSaturation : + 1.0f); + glUniform1f(shader.sdrBrightness, + modifySDR && m_RenderData.pMonitor->sdrBrightness > 0 && targetImageDescription.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ ? + m_RenderData.pMonitor->sdrBrightness : + 1.0f); +} + +void CHyprOpenGLImpl::passCMUniforms(const CShader& shader, const SImageDescription& imageDescription) { + passCMUniforms(shader, imageDescription, m_RenderData.pMonitor->imageDescription, true); +} + void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, const CBox& box, float alpha, const CRegion& damage, int round, float roundingPower, bool discardActive, bool noAA, bool allowCustomUV, bool allowDim) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); @@ -1347,28 +1512,30 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, const CB auto texType = tex->m_iType; if (CRASHING) { - shader = &m_RenderData.pCurrentMonData->m_shGLITCH; + shader = &m_shaders->m_shGLITCH; usingFinalShader = true; } else if (m_bApplyFinalShader && m_sFinalScreenShader.program) { shader = &m_sFinalScreenShader; usingFinalShader = true; } else { if (m_bApplyFinalShader) { - shader = &m_RenderData.pCurrentMonData->m_shPASSTHRURGBA; + shader = &m_shaders->m_shPASSTHRURGBA; usingFinalShader = true; } else { switch (tex->m_iType) { - case TEXTURE_RGBA: shader = &m_RenderData.pCurrentMonData->m_shRGBA; break; - case TEXTURE_RGBX: shader = &m_RenderData.pCurrentMonData->m_shRGBX; break; + case TEXTURE_RGBA: shader = &m_shaders->m_shRGBA; break; + case TEXTURE_RGBX: shader = &m_shaders->m_shRGBX; break; - case TEXTURE_EXTERNAL: shader = &m_RenderData.pCurrentMonData->m_shEXT; break; // might be unused + case TEXTURE_EXTERNAL: shader = &m_shaders->m_shEXT; break; // might be unused default: RASSERT(false, "tex->m_iTarget unsupported!"); } } } - if (m_RenderData.currentWindow && m_RenderData.currentWindow->m_sWindowData.RGBX.valueOrDefault()) + if (m_RenderData.currentWindow && m_RenderData.currentWindow->m_sWindowData.RGBX.valueOrDefault()) { + shader = &m_shaders->m_shRGBX; texType = TEXTURE_RGBX; + } glActiveTexture(GL_TEXTURE0); glBindTexture(tex->m_iTarget, tex->m_iTexID); @@ -1387,56 +1554,21 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, const CB const auto imageDescription = m_RenderData.surface.valid() && m_RenderData.surface->colorManagement.valid() ? m_RenderData.surface->colorManagement->imageDescription() : SImageDescription{}; - const bool skipCM = !*PENABLECM /* CM disabled by the user */ - || !m_RenderData.surface /* FIXME unknown texture settings should be treated as sRGB and go through CM if monitor isn't in sRGB mode */ - || !m_bCMSupported /* CM unsupported - hw failed to compile the shader probably */ + const bool skipCM = !*PENABLECM || !m_bCMSupported /* CM unsupported or disabled */ || (imageDescription == m_RenderData.pMonitor->imageDescription) /* Source and target have the same image description */ || ((*PPASS == 1 || (*PPASS == 2 && imageDescription.transferFunction == CM_TRANSFER_FUNCTION_ST2084_PQ)) && m_RenderData.pMonitor->activeWorkspace && m_RenderData.pMonitor->activeWorkspace->m_bHasFullscreenWindow && m_RenderData.pMonitor->activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN) /* Fullscreen window with pass cm enabled */; + if (!skipCM && !usingFinalShader && (texType == TEXTURE_RGBA || texType == TEXTURE_RGBX)) + shader = &m_shaders->m_shCM; + glUseProgram(shader->program); -#ifndef GLES2 - if (!skipCM && !usingFinalShader && (texType == TEXTURE_RGBA || texType == TEXTURE_RGBX)) { - shader = &m_RenderData.pCurrentMonData->m_shCM; - glUseProgram(shader->program); + if (shader == &m_shaders->m_shCM) { glUniform1i(shader->texType, texType); - const auto imageDescription = - m_RenderData.surface && m_RenderData.surface->colorManagement ? m_RenderData.surface->colorManagement->imageDescription() : SImageDescription{}; - glUniform1i(shader->sourceTF, imageDescription.transferFunction); - glUniform1i(shader->targetTF, m_RenderData.pMonitor->imageDescription.transferFunction); - const auto sourcePrimaries = - imageDescription.primariesNameSet || imageDescription.primaries == SPCPRimaries{} ? getPrimaries(imageDescription.primariesNamed) : imageDescription.primaries; - const auto targetPrimaries = m_RenderData.pMonitor->imageDescription.primariesNameSet || m_RenderData.pMonitor->imageDescription.primaries == SPCPRimaries{} ? - getPrimaries(m_RenderData.pMonitor->imageDescription.primariesNamed) : - m_RenderData.pMonitor->imageDescription.primaries; - - const GLfloat glSourcePrimaries[8] = { - sourcePrimaries.red.x, sourcePrimaries.red.y, sourcePrimaries.green.x, sourcePrimaries.green.y, - sourcePrimaries.blue.x, sourcePrimaries.blue.y, sourcePrimaries.white.x, sourcePrimaries.white.y, - }; - const GLfloat glTargetPrimaries[8] = { - targetPrimaries.red.x, targetPrimaries.red.y, targetPrimaries.green.x, targetPrimaries.green.y, - targetPrimaries.blue.x, targetPrimaries.blue.y, targetPrimaries.white.x, targetPrimaries.white.y, - }; - glUniformMatrix4x2fv(shader->sourcePrimaries, 1, false, glSourcePrimaries); - glUniformMatrix4x2fv(shader->targetPrimaries, 1, false, glTargetPrimaries); - - const float maxLuminance = imageDescription.luminances.max > 0 ? imageDescription.luminances.max : imageDescription.luminances.reference; - glUniform1f(shader->maxLuminance, maxLuminance * m_RenderData.pMonitor->imageDescription.luminances.reference / imageDescription.luminances.reference); - glUniform1f(shader->dstMaxLuminance, m_RenderData.pMonitor->imageDescription.luminances.max > 0 ? m_RenderData.pMonitor->imageDescription.luminances.max : 10000); - glUniform1f(shader->dstRefLuminance, m_RenderData.pMonitor->imageDescription.luminances.reference); - glUniform1f(shader->sdrSaturation, - m_RenderData.pMonitor->sdrSaturation > 0 && m_RenderData.pMonitor->imageDescription.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ ? - m_RenderData.pMonitor->sdrSaturation : - 1.0f); - glUniform1f(shader->sdrBrightness, - m_RenderData.pMonitor->sdrBrightness > 0 && m_RenderData.pMonitor->imageDescription.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ ? - m_RenderData.pMonitor->sdrBrightness : - 1.0f); + passCMUniforms(*shader, imageDescription); } -#endif #ifndef GLES2 glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix.getMatrix().data()); @@ -1568,7 +1700,7 @@ void CHyprOpenGLImpl::renderTexturePrimitive(SP tex, const CBox& box) Mat3x3 matrix = m_RenderData.monitorProjection.projectBox(newBox, TRANSFORM, newBox.rot); Mat3x3 glMatrix = m_RenderData.projection.copy().multiply(matrix); - CShader* shader = &m_RenderData.pCurrentMonData->m_shPASSTHRURGBA; + CShader* shader = &m_shaders->m_shPASSTHRURGBA; glActiveTexture(GL_TEXTURE0); glBindTexture(tex->m_iTarget, tex->m_iTexID); @@ -1619,7 +1751,7 @@ void CHyprOpenGLImpl::renderTextureMatte(SP tex, const CBox& box, CFra Mat3x3 matrix = m_RenderData.monitorProjection.projectBox(newBox, TRANSFORM, newBox.rot); Mat3x3 glMatrix = m_RenderData.projection.copy().multiply(matrix); - CShader* shader = &m_RenderData.pCurrentMonData->m_shMATTE; + CShader* shader = &m_shaders->m_shMATTE; glUseProgram(shader->program); @@ -1715,23 +1847,38 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o glTexParameteri(currentTex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glUseProgram(m_RenderData.pCurrentMonData->m_shBLURPREPARE.program); + glUseProgram(m_shaders->m_shBLURPREPARE.program); + + // From FB to sRGB + const bool skipCM = !m_bCMSupported || m_RenderData.pMonitor->imageDescription == SImageDescription{}; + glUniform1i(m_shaders->m_shBLURPREPARE.skipCM, skipCM); + if (!skipCM) { + passCMUniforms(m_shaders->m_shBLURPREPARE, m_RenderData.pMonitor->imageDescription, SImageDescription{}); + glUniform1f(m_shaders->m_shBLURPREPARE.sdrSaturation, + m_RenderData.pMonitor->sdrSaturation > 0 && m_RenderData.pMonitor->imageDescription.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ ? + m_RenderData.pMonitor->sdrSaturation : + 1.0f); + glUniform1f(m_shaders->m_shBLURPREPARE.sdrBrightness, + m_RenderData.pMonitor->sdrBrightness > 0 && m_RenderData.pMonitor->imageDescription.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ ? + m_RenderData.pMonitor->sdrBrightness : + 1.0f); + } #ifndef GLES2 - glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURPREPARE.proj, 1, GL_TRUE, glMatrix.getMatrix().data()); + glUniformMatrix3fv(m_shaders->m_shBLURPREPARE.proj, 1, GL_TRUE, glMatrix.getMatrix().data()); #else glMatrix.transpose(); - glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURPREPARE.proj, 1, GL_FALSE, glMatrix.getMatrix().data()); + glUniformMatrix3fv(m_shaders->m_shBLURPREPARE.proj, 1, GL_FALSE, glMatrix.getMatrix().data()); #endif - glUniform1f(m_RenderData.pCurrentMonData->m_shBLURPREPARE.contrast, *PBLURCONTRAST); - glUniform1f(m_RenderData.pCurrentMonData->m_shBLURPREPARE.brightness, *PBLURBRIGHTNESS); - glUniform1i(m_RenderData.pCurrentMonData->m_shBLURPREPARE.tex, 0); + glUniform1f(m_shaders->m_shBLURPREPARE.contrast, *PBLURCONTRAST); + glUniform1f(m_shaders->m_shBLURPREPARE.brightness, *PBLURBRIGHTNESS); + glUniform1i(m_shaders->m_shBLURPREPARE.tex, 0); - glVertexAttribPointer(m_RenderData.pCurrentMonData->m_shBLURPREPARE.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); - glVertexAttribPointer(m_RenderData.pCurrentMonData->m_shBLURPREPARE.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); + glVertexAttribPointer(m_shaders->m_shBLURPREPARE.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); + glVertexAttribPointer(m_shaders->m_shBLURPREPARE.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); - glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBLURPREPARE.posAttrib); - glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBLURPREPARE.texAttrib); + glEnableVertexAttribArray(m_shaders->m_shBLURPREPARE.posAttrib); + glEnableVertexAttribArray(m_shaders->m_shBLURPREPARE.texAttrib); if (!damage.empty()) { for (auto const& RECT : damage.getRects()) { @@ -1740,8 +1887,8 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o } } - glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBLURPREPARE.posAttrib); - glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBLURPREPARE.texAttrib); + glDisableVertexAttribArray(m_shaders->m_shBLURPREPARE.posAttrib); + glDisableVertexAttribArray(m_shaders->m_shBLURPREPARE.texAttrib); currentRenderToFB = PMIRRORSWAPFB; } @@ -1771,15 +1918,13 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o glUniformMatrix3fv(pShader->proj, 1, GL_FALSE, glMatrix.getMatrix().data()); #endif glUniform1f(pShader->radius, *PBLURSIZE * a); // this makes the blursize change with a - if (pShader == &m_RenderData.pCurrentMonData->m_shBLUR1) { - glUniform2f(m_RenderData.pCurrentMonData->m_shBLUR1.halfpixel, 0.5f / (m_RenderData.pMonitor->vecPixelSize.x / 2.f), - 0.5f / (m_RenderData.pMonitor->vecPixelSize.y / 2.f)); - glUniform1i(m_RenderData.pCurrentMonData->m_shBLUR1.passes, *PBLURPASSES); - glUniform1f(m_RenderData.pCurrentMonData->m_shBLUR1.vibrancy, *PBLURVIBRANCY); - glUniform1f(m_RenderData.pCurrentMonData->m_shBLUR1.vibrancy_darkness, *PBLURVIBRANCYDARKNESS); + if (pShader == &m_shaders->m_shBLUR1) { + glUniform2f(m_shaders->m_shBLUR1.halfpixel, 0.5f / (m_RenderData.pMonitor->vecPixelSize.x / 2.f), 0.5f / (m_RenderData.pMonitor->vecPixelSize.y / 2.f)); + glUniform1i(m_shaders->m_shBLUR1.passes, *PBLURPASSES); + glUniform1f(m_shaders->m_shBLUR1.vibrancy, *PBLURVIBRANCY); + glUniform1f(m_shaders->m_shBLUR1.vibrancy_darkness, *PBLURVIBRANCYDARKNESS); } else - glUniform2f(m_RenderData.pCurrentMonData->m_shBLUR2.halfpixel, 0.5f / (m_RenderData.pMonitor->vecPixelSize.x * 2.f), - 0.5f / (m_RenderData.pMonitor->vecPixelSize.y * 2.f)); + glUniform2f(m_shaders->m_shBLUR2.halfpixel, 0.5f / (m_RenderData.pMonitor->vecPixelSize.x * 2.f), 0.5f / (m_RenderData.pMonitor->vecPixelSize.y * 2.f)); glUniform1i(pShader->tex, 0); glVertexAttribPointer(pShader->posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); @@ -1815,12 +1960,12 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o // and draw for (auto i = 1; i <= *PBLURPASSES; ++i) { tempDamage = damage.copy().scale(1.f / (1 << i)); - drawPass(&m_RenderData.pCurrentMonData->m_shBLUR1, &tempDamage); // down + drawPass(&m_shaders->m_shBLUR1, &tempDamage); // down } for (auto i = *PBLURPASSES - 1; i >= 0; --i) { - tempDamage = damage.copy().scale(1.f / (1 << i)); // when upsampling we make the region twice as big - drawPass(&m_RenderData.pCurrentMonData->m_shBLUR2, &tempDamage); // up + tempDamage = damage.copy().scale(1.f / (1 << i)); // when upsampling we make the region twice as big + drawPass(&m_shaders->m_shBLUR2, &tempDamage); // up } // finalize the image @@ -1841,24 +1986,24 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o glTexParameteri(currentTex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glUseProgram(m_RenderData.pCurrentMonData->m_shBLURFINISH.program); + glUseProgram(m_shaders->m_shBLURFINISH.program); #ifndef GLES2 - glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURFINISH.proj, 1, GL_TRUE, glMatrix.getMatrix().data()); + glUniformMatrix3fv(m_shaders->m_shBLURFINISH.proj, 1, GL_TRUE, glMatrix.getMatrix().data()); #else glMatrix.transpose(); - glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURFINISH.proj, 1, GL_FALSE, glMatrix.getMatrix().data()); + glUniformMatrix3fv(m_shaders->m_shBLURFINISH.proj, 1, GL_FALSE, glMatrix.getMatrix().data()); #endif - glUniform1f(m_RenderData.pCurrentMonData->m_shBLURFINISH.noise, *PBLURNOISE); - glUniform1f(m_RenderData.pCurrentMonData->m_shBLURFINISH.brightness, *PBLURBRIGHTNESS); + glUniform1f(m_shaders->m_shBLURFINISH.noise, *PBLURNOISE); + glUniform1f(m_shaders->m_shBLURFINISH.brightness, *PBLURBRIGHTNESS); - glUniform1i(m_RenderData.pCurrentMonData->m_shBLURFINISH.tex, 0); + glUniform1i(m_shaders->m_shBLURFINISH.tex, 0); - glVertexAttribPointer(m_RenderData.pCurrentMonData->m_shBLURFINISH.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); - glVertexAttribPointer(m_RenderData.pCurrentMonData->m_shBLURFINISH.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); + glVertexAttribPointer(m_shaders->m_shBLURFINISH.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); + glVertexAttribPointer(m_shaders->m_shBLURFINISH.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); - glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBLURFINISH.posAttrib); - glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBLURFINISH.texAttrib); + glEnableVertexAttribArray(m_shaders->m_shBLURFINISH.posAttrib); + glEnableVertexAttribArray(m_shaders->m_shBLURFINISH.texAttrib); if (!damage.empty()) { for (auto const& RECT : damage.getRects()) { @@ -1867,8 +2012,8 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o } } - glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBLURFINISH.posAttrib); - glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBLURFINISH.texAttrib); + glDisableVertexAttribArray(m_shaders->m_shBLURFINISH.posAttrib); + glDisableVertexAttribArray(m_shaders->m_shBLURFINISH.texAttrib); if (currentRenderToFB != PMIRRORFB) currentRenderToFB = PMIRRORFB; @@ -2184,20 +2329,25 @@ void CHyprOpenGLImpl::renderBorder(const CBox& box, const CGradientValueData& gr const auto BLEND = m_bBlend; blend(true); - glUseProgram(m_RenderData.pCurrentMonData->m_shBORDER1.program); + glUseProgram(m_shaders->m_shBORDER1.program); + + const bool skipCM = !m_bCMSupported || m_RenderData.pMonitor->imageDescription == SImageDescription{}; + glUniform1i(m_shaders->m_shBORDER1.skipCM, skipCM); + if (!skipCM) + passCMUniforms(m_shaders->m_shBORDER1, SImageDescription{}); #ifndef GLES2 - glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBORDER1.proj, 1, GL_TRUE, glMatrix.getMatrix().data()); + glUniformMatrix3fv(m_shaders->m_shBORDER1.proj, 1, GL_TRUE, glMatrix.getMatrix().data()); #else glMatrix.transpose(); - glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBORDER1.proj, 1, GL_FALSE, glMatrix.getMatrix().data()); + glUniformMatrix3fv(m_shaders->m_shBORDER1.proj, 1, GL_FALSE, glMatrix.getMatrix().data()); #endif - glUniform4fv(m_RenderData.pCurrentMonData->m_shBORDER1.gradient, grad.m_vColorsOkLabA.size() / 4, (float*)grad.m_vColorsOkLabA.data()); - glUniform1i(m_RenderData.pCurrentMonData->m_shBORDER1.gradientLength, grad.m_vColorsOkLabA.size() / 4); - glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.angle, (int)(grad.m_fAngle / (PI / 180.0)) % 360 * (PI / 180.0)); - glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.alpha, a); - glUniform1i(m_RenderData.pCurrentMonData->m_shBORDER1.gradient2Length, 0); + glUniform4fv(m_shaders->m_shBORDER1.gradient, grad.m_vColorsOkLabA.size() / 4, (float*)grad.m_vColorsOkLabA.data()); + glUniform1i(m_shaders->m_shBORDER1.gradientLength, grad.m_vColorsOkLabA.size() / 4); + glUniform1f(m_shaders->m_shBORDER1.angle, (int)(grad.m_fAngle / (PI / 180.0)) % 360 * (PI / 180.0)); + glUniform1f(m_shaders->m_shBORDER1.alpha, a); + glUniform1i(m_shaders->m_shBORDER1.gradient2Length, 0); CBox transformedBox = newBox; transformedBox.transform(wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x, @@ -2206,19 +2356,19 @@ void CHyprOpenGLImpl::renderBorder(const CBox& box, const CGradientValueData& gr const auto TOPLEFT = Vector2D(transformedBox.x, transformedBox.y); const auto FULLSIZE = Vector2D(transformedBox.width, transformedBox.height); - glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y); - glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y); - glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.fullSizeUntransformed, (float)newBox.width, (float)newBox.height); - glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.radius, round); - glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.radiusOuter, outerRound == -1 ? round : outerRound); - glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.roundingPower, roundingPower); - glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.thick, scaledBorderSize); + glUniform2f(m_shaders->m_shBORDER1.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y); + glUniform2f(m_shaders->m_shBORDER1.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y); + glUniform2f(m_shaders->m_shBORDER1.fullSizeUntransformed, (float)newBox.width, (float)newBox.height); + glUniform1f(m_shaders->m_shBORDER1.radius, round); + glUniform1f(m_shaders->m_shBORDER1.radiusOuter, outerRound == -1 ? round : outerRound); + glUniform1f(m_shaders->m_shBORDER1.roundingPower, roundingPower); + glUniform1f(m_shaders->m_shBORDER1.thick, scaledBorderSize); - glVertexAttribPointer(m_RenderData.pCurrentMonData->m_shBORDER1.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); - glVertexAttribPointer(m_RenderData.pCurrentMonData->m_shBORDER1.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); + glVertexAttribPointer(m_shaders->m_shBORDER1.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); + glVertexAttribPointer(m_shaders->m_shBORDER1.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); - glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBORDER1.posAttrib); - glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBORDER1.texAttrib); + glEnableVertexAttribArray(m_shaders->m_shBORDER1.posAttrib); + glEnableVertexAttribArray(m_shaders->m_shBORDER1.texAttrib); if (m_RenderData.clipBox.width != 0 && m_RenderData.clipBox.height != 0) { CRegion damageClip{m_RenderData.clipBox.x, m_RenderData.clipBox.y, m_RenderData.clipBox.width, m_RenderData.clipBox.height}; @@ -2237,8 +2387,8 @@ void CHyprOpenGLImpl::renderBorder(const CBox& box, const CGradientValueData& gr } } - glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBORDER1.posAttrib); - glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBORDER1.texAttrib); + glDisableVertexAttribArray(m_shaders->m_shBORDER1.posAttrib); + glDisableVertexAttribArray(m_shaders->m_shBORDER1.texAttrib); blend(BLEND); } @@ -2277,24 +2427,24 @@ void CHyprOpenGLImpl::renderBorder(const CBox& box, const CGradientValueData& gr const auto BLEND = m_bBlend; blend(true); - glUseProgram(m_RenderData.pCurrentMonData->m_shBORDER1.program); + glUseProgram(m_shaders->m_shBORDER1.program); #ifndef GLES2 - glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBORDER1.proj, 1, GL_TRUE, glMatrix.getMatrix().data()); + glUniformMatrix3fv(m_shaders->m_shBORDER1.proj, 1, GL_TRUE, glMatrix.getMatrix().data()); #else glMatrix.transpose(); - glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBORDER1.proj, 1, GL_FALSE, glMatrix.getMatrix().data()); + glUniformMatrix3fv(m_shaders->m_shBORDER1.proj, 1, GL_FALSE, glMatrix.getMatrix().data()); #endif - glUniform4fv(m_RenderData.pCurrentMonData->m_shBORDER1.gradient, grad1.m_vColorsOkLabA.size() / 4, (float*)grad1.m_vColorsOkLabA.data()); - glUniform1i(m_RenderData.pCurrentMonData->m_shBORDER1.gradientLength, grad1.m_vColorsOkLabA.size() / 4); - glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.angle, (int)(grad1.m_fAngle / (PI / 180.0)) % 360 * (PI / 180.0)); + glUniform4fv(m_shaders->m_shBORDER1.gradient, grad1.m_vColorsOkLabA.size() / 4, (float*)grad1.m_vColorsOkLabA.data()); + glUniform1i(m_shaders->m_shBORDER1.gradientLength, grad1.m_vColorsOkLabA.size() / 4); + glUniform1f(m_shaders->m_shBORDER1.angle, (int)(grad1.m_fAngle / (PI / 180.0)) % 360 * (PI / 180.0)); if (grad2.m_vColorsOkLabA.size() > 0) - glUniform4fv(m_RenderData.pCurrentMonData->m_shBORDER1.gradient2, grad2.m_vColorsOkLabA.size() / 4, (float*)grad2.m_vColorsOkLabA.data()); - glUniform1i(m_RenderData.pCurrentMonData->m_shBORDER1.gradient2Length, grad2.m_vColorsOkLabA.size() / 4); - glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.angle2, (int)(grad2.m_fAngle / (PI / 180.0)) % 360 * (PI / 180.0)); - glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.alpha, a); - glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.gradientLerp, lerp); + glUniform4fv(m_shaders->m_shBORDER1.gradient2, grad2.m_vColorsOkLabA.size() / 4, (float*)grad2.m_vColorsOkLabA.data()); + glUniform1i(m_shaders->m_shBORDER1.gradient2Length, grad2.m_vColorsOkLabA.size() / 4); + glUniform1f(m_shaders->m_shBORDER1.angle2, (int)(grad2.m_fAngle / (PI / 180.0)) % 360 * (PI / 180.0)); + glUniform1f(m_shaders->m_shBORDER1.alpha, a); + glUniform1f(m_shaders->m_shBORDER1.gradientLerp, lerp); CBox transformedBox = newBox; transformedBox.transform(wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x, @@ -2303,19 +2453,19 @@ void CHyprOpenGLImpl::renderBorder(const CBox& box, const CGradientValueData& gr const auto TOPLEFT = Vector2D(transformedBox.x, transformedBox.y); const auto FULLSIZE = Vector2D(transformedBox.width, transformedBox.height); - glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y); - glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y); - glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.fullSizeUntransformed, (float)newBox.width, (float)newBox.height); - glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.radius, round); - glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.radiusOuter, outerRound == -1 ? round : outerRound); - glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.roundingPower, roundingPower); - glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.thick, scaledBorderSize); + glUniform2f(m_shaders->m_shBORDER1.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y); + glUniform2f(m_shaders->m_shBORDER1.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y); + glUniform2f(m_shaders->m_shBORDER1.fullSizeUntransformed, (float)newBox.width, (float)newBox.height); + glUniform1f(m_shaders->m_shBORDER1.radius, round); + glUniform1f(m_shaders->m_shBORDER1.radiusOuter, outerRound == -1 ? round : outerRound); + glUniform1f(m_shaders->m_shBORDER1.roundingPower, roundingPower); + glUniform1f(m_shaders->m_shBORDER1.thick, scaledBorderSize); - glVertexAttribPointer(m_RenderData.pCurrentMonData->m_shBORDER1.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); - glVertexAttribPointer(m_RenderData.pCurrentMonData->m_shBORDER1.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); + glVertexAttribPointer(m_shaders->m_shBORDER1.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); + glVertexAttribPointer(m_shaders->m_shBORDER1.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); - glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBORDER1.posAttrib); - glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBORDER1.texAttrib); + glEnableVertexAttribArray(m_shaders->m_shBORDER1.posAttrib); + glEnableVertexAttribArray(m_shaders->m_shBORDER1.texAttrib); if (m_RenderData.clipBox.width != 0 && m_RenderData.clipBox.height != 0) { CRegion damageClip{m_RenderData.clipBox.x, m_RenderData.clipBox.y, m_RenderData.clipBox.width, m_RenderData.clipBox.height}; @@ -2334,8 +2484,8 @@ void CHyprOpenGLImpl::renderBorder(const CBox& box, const CGradientValueData& gr } } - glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBORDER1.posAttrib); - glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBORDER1.texAttrib); + glDisableVertexAttribArray(m_shaders->m_shBORDER1.posAttrib); + glDisableVertexAttribArray(m_shaders->m_shBORDER1.texAttrib); blend(BLEND); } @@ -2365,34 +2515,38 @@ void CHyprOpenGLImpl::renderRoundedShadow(const CBox& box, int round, float roun blend(true); - glUseProgram(m_RenderData.pCurrentMonData->m_shSHADOW.program); + glUseProgram(m_shaders->m_shSHADOW.program); + const bool skipCM = !m_bCMSupported || m_RenderData.pMonitor->imageDescription == SImageDescription{}; + glUniform1i(m_shaders->m_shSHADOW.skipCM, skipCM); + if (!skipCM) + passCMUniforms(m_shaders->m_shSHADOW, SImageDescription{}); #ifndef GLES2 - glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shSHADOW.proj, 1, GL_TRUE, glMatrix.getMatrix().data()); + glUniformMatrix3fv(m_shaders->m_shSHADOW.proj, 1, GL_TRUE, glMatrix.getMatrix().data()); #else glMatrix.transpose(); - glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shSHADOW.proj, 1, GL_FALSE, glMatrix.getMatrix().data()); + glUniformMatrix3fv(m_shaders->m_shSHADOW.proj, 1, GL_FALSE, glMatrix.getMatrix().data()); #endif - glUniform4f(m_RenderData.pCurrentMonData->m_shSHADOW.color, col.r, col.g, col.b, col.a * a); + glUniform4f(m_shaders->m_shSHADOW.color, col.r, col.g, col.b, col.a * a); const auto TOPLEFT = Vector2D(range + round, range + round); const auto BOTTOMRIGHT = Vector2D(newBox.width - (range + round), newBox.height - (range + round)); const auto FULLSIZE = Vector2D(newBox.width, newBox.height); // Rounded corners - glUniform2f(m_RenderData.pCurrentMonData->m_shSHADOW.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y); - glUniform2f(m_RenderData.pCurrentMonData->m_shSHADOW.bottomRight, (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y); - glUniform2f(m_RenderData.pCurrentMonData->m_shSHADOW.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y); - glUniform1f(m_RenderData.pCurrentMonData->m_shSHADOW.radius, range + round); - glUniform1f(m_RenderData.pCurrentMonData->m_shSHADOW.roundingPower, roundingPower); - glUniform1f(m_RenderData.pCurrentMonData->m_shSHADOW.range, range); - glUniform1f(m_RenderData.pCurrentMonData->m_shSHADOW.shadowPower, SHADOWPOWER); + glUniform2f(m_shaders->m_shSHADOW.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y); + glUniform2f(m_shaders->m_shSHADOW.bottomRight, (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y); + glUniform2f(m_shaders->m_shSHADOW.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y); + glUniform1f(m_shaders->m_shSHADOW.radius, range + round); + glUniform1f(m_shaders->m_shSHADOW.roundingPower, roundingPower); + glUniform1f(m_shaders->m_shSHADOW.range, range); + glUniform1f(m_shaders->m_shSHADOW.shadowPower, SHADOWPOWER); - glVertexAttribPointer(m_RenderData.pCurrentMonData->m_shSHADOW.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); - glVertexAttribPointer(m_RenderData.pCurrentMonData->m_shSHADOW.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); + glVertexAttribPointer(m_shaders->m_shSHADOW.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); + glVertexAttribPointer(m_shaders->m_shSHADOW.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); - glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shSHADOW.posAttrib); - glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shSHADOW.texAttrib); + glEnableVertexAttribArray(m_shaders->m_shSHADOW.posAttrib); + glEnableVertexAttribArray(m_shaders->m_shSHADOW.texAttrib); if (m_RenderData.clipBox.width != 0 && m_RenderData.clipBox.height != 0) { CRegion damageClip{m_RenderData.clipBox.x, m_RenderData.clipBox.y, m_RenderData.clipBox.width, m_RenderData.clipBox.height}; @@ -2411,8 +2565,8 @@ void CHyprOpenGLImpl::renderRoundedShadow(const CBox& box, int round, float roun } } - glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shSHADOW.posAttrib); - glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shSHADOW.texAttrib); + glDisableVertexAttribArray(m_shaders->m_shSHADOW.posAttrib); + glDisableVertexAttribArray(m_shaders->m_shSHADOW.texAttrib); } void CHyprOpenGLImpl::saveBufferForMirror(const CBox& box) { @@ -3021,7 +3175,7 @@ CEGLSync::~CEGLSync() { if (sync == EGL_NO_SYNC_KHR) return; - if (g_pHyprOpenGL && g_pHyprOpenGL->m_sProc.eglDestroySyncKHR(g_pHyprOpenGL->m_pEglDisplay, sync) != EGL_TRUE) + if (g_pHyprOpenGL->m_sProc.eglDestroySyncKHR(g_pHyprOpenGL->m_pEglDisplay, sync) != EGL_TRUE) Debug::log(ERR, "eglDestroySyncKHR failed"); } diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 34bb7e9c5..c3091f153 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -9,6 +9,7 @@ #include "../helpers/sync/SyncTimeline.hpp" #include #include +#include #include #include @@ -78,6 +79,26 @@ enum eMonitorExtraRenderFBs : uint8_t { FB_MONITOR_RENDER_EXTRA_BLUR, }; +struct SPreparedShaders { + std::string TEXVERTSRC; + std::string TEXVERTSRC300; + std::string TEXVERTSRC320; + CShader m_shQUAD; + CShader m_shRGBA; + CShader m_shPASSTHRURGBA; + CShader m_shMATTE; + CShader m_shRGBX; + CShader m_shEXT; + CShader m_shBLUR1; + CShader m_shBLUR2; + CShader m_shBLURPREPARE; + CShader m_shBLURFINISH; + CShader m_shSHADOW; + CShader m_shBORDER1; + CShader m_shGLITCH; + CShader m_shCM; +}; + struct SMonitorRenderData { CFramebuffer offloadFB; CFramebuffer mirrorFB; // these are used for some effects, @@ -90,23 +111,6 @@ struct SMonitorRenderData { bool blurFBDirty = true; bool blurFBShouldRender = false; - - // Shaders - bool m_bShadersInitialized = false; - CShader m_shQUAD; - CShader m_shRGBA; - CShader m_shPASSTHRURGBA; - CShader m_shMATTE; - CShader m_shRGBX; - CShader m_shEXT; - CShader m_shBLUR1; - CShader m_shBLUR2; - CShader m_shBLURPREPARE; - CShader m_shBLURFINISH; - CShader m_shSHADOW; - CShader m_shBORDER1; - CShader m_shGLITCH; - CShader m_shCM; }; struct SCurrentRenderData { @@ -232,6 +236,10 @@ class CHyprOpenGLImpl { EGLImageKHR createEGLImage(const Aquamarine::SDMABUFAttrs& attrs); SP createEGLSync(int fence = -1); + bool initShaders(); + bool m_bShadersInitialized = false; + SP m_shaders; + SCurrentRenderData m_RenderData; Hyprutils::OS::CFileDescriptor m_iGBMFD; @@ -309,7 +317,6 @@ class CHyprOpenGLImpl { GLuint createProgram(const std::string&, const std::string&, bool dynamic = false, bool silent = false); GLuint compileShader(const GLuint&, std::string, bool dynamic = false, bool silent = false); void createBGTextureForMonitor(PHLMONITOR); - void initShaders(); void initDRMFormats(); void initEGL(bool gbm); EGLDeviceEXT eglDeviceFromDRMFD(int drmFD); @@ -322,6 +329,9 @@ class CHyprOpenGLImpl { // returns the out FB, can be either Mirror or MirrorSwap CFramebuffer* blurMainFramebufferWithDamage(float a, CRegion* damage); + void passCMUniforms(const CShader&, const NColorManagement::SImageDescription& imageDescription, const NColorManagement::SImageDescription& targetImageDescription, + bool modifySDR = false); + void passCMUniforms(const CShader&, const NColorManagement::SImageDescription& imageDescription); void renderTextureInternalWithDamage(SP, const CBox& box, float a, const CRegion& damage, int round = 0, float roundingPower = 2.0f, bool discardOpaque = false, bool noAA = false, bool allowCustomUV = false, bool allowDim = false); void renderTexturePrimitive(SP tex, const CBox& box); diff --git a/src/render/Shader.cpp b/src/render/Shader.cpp index 984d8ce35..97bcf7613 100644 --- a/src/render/Shader.cpp +++ b/src/render/Shader.cpp @@ -1,17 +1,5 @@ #include "Shader.hpp" -GLint CShader::getUniformLocation(const std::string& unif) { - const auto itpos = m_muUniforms.find(unif); - - if (itpos == m_muUniforms.end()) { - const auto unifLoc = glGetUniformLocation(program, unif.c_str()); - m_muUniforms[unif] = unifLoc; - return unifLoc; - } - - return itpos->second; -} - CShader::~CShader() { destroy(); } diff --git a/src/render/Shader.hpp b/src/render/Shader.hpp index 413f3ef0f..1d21894c4 100644 --- a/src/render/Shader.hpp +++ b/src/render/Shader.hpp @@ -12,6 +12,7 @@ class CShader { GLint color = -1; GLint alphaMatte = -1; GLint texType = -1; + GLint skipCM = -1; GLint sourceTF = -1; GLint targetTF = -1; GLint sourcePrimaries = -1; @@ -74,8 +75,6 @@ class CShader { GLint brightness = -1; GLint noise = -1; - GLint getUniformLocation(const std::string&); - void destroy(); private: diff --git a/src/render/Shaders.hpp b/src/render/Shaders.hpp deleted file mode 100644 index 1849c621a..000000000 --- a/src/render/Shaders.hpp +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -#include "shaders/Textures.hpp" -#include "shaders/Shadow.hpp" -#include "shaders/Border.hpp" \ No newline at end of file diff --git a/src/render/shaders/SharedValues.hpp b/src/render/shaders/SharedValues.hpp deleted file mode 100644 index 9a74c8922..000000000 --- a/src/render/shaders/SharedValues.hpp +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -constexpr float SHADER_ROUNDED_SMOOTHING_FACTOR = M_PI / 5.34665792551; \ No newline at end of file diff --git a/src/render/shaders/Textures.hpp b/src/render/shaders/Textures.hpp deleted file mode 100644 index 002c34598..000000000 --- a/src/render/shaders/Textures.hpp +++ /dev/null @@ -1,541 +0,0 @@ -#pragma once - -#include -#include -#include "SharedValues.hpp" - -inline static constexpr auto ROUNDED_SHADER_FUNC = [](const std::string colorVarName) -> std::string { - return R"#( - - // shoutout me: I fixed this shader being a bit pixelated while watching hentai - - highp vec2 pixCoord = vec2(gl_FragCoord); - pixCoord -= topLeft + fullSize * 0.5; - pixCoord *= vec2(lessThan(pixCoord, vec2(0.0))) * -2.0 + 1.0; - pixCoord -= fullSize * 0.5 - radius; - pixCoord += vec2(1.0, 1.0) / fullSize; // center the pix dont make it top-left - - // smoothing constant for the edge: more = blurrier, but smoother - const float SMOOTHING_CONSTANT = )#" + - std::format("{:.7f}", SHADER_ROUNDED_SMOOTHING_FACTOR) + R"#(; - - if (pixCoord.x + pixCoord.y > radius) { - - float dist = pow(pow(pixCoord.x, roundingPower) + pow(pixCoord.y, roundingPower), 1.0/roundingPower); - - if (dist > radius + SMOOTHING_CONSTANT) - discard; - - float normalized = 1.0 - smoothstep(0.0, 1.0, (dist - radius + SMOOTHING_CONSTANT) / (SMOOTHING_CONSTANT * 2.0)); - - )#" + - colorVarName + R"#( = )#" + colorVarName + R"#( * normalized; - } -)#"; -}; - -inline const std::string QUADVERTSRC = R"#( -uniform mat3 proj; -uniform vec4 color; -attribute vec2 pos; -attribute vec2 texcoord; -attribute vec2 texcoordMatte; -varying vec4 v_color; -varying vec2 v_texcoord; -varying vec2 v_texcoordMatte; - -void main() { - gl_Position = vec4(proj * vec3(pos, 1.0), 1.0); - v_color = color; - v_texcoord = texcoord; - v_texcoordMatte = texcoordMatte; -})#"; - -inline const std::string QUADFRAGSRC = R"#( -precision highp float; -varying vec4 v_color; - -uniform vec2 topLeft; -uniform vec2 fullSize; -uniform float radius; -uniform float roundingPower; - -void main() { - - vec4 pixColor = v_color; - - if (radius > 0.0) { - )#" + - ROUNDED_SHADER_FUNC("pixColor") + R"#( - } - - gl_FragColor = pixColor; -})#"; - -inline const std::string TEXVERTSRC = R"#( -uniform mat3 proj; -attribute vec2 pos; -attribute vec2 texcoord; -varying vec2 v_texcoord; - -void main() { - gl_Position = vec4(proj * vec3(pos, 1.0), 1.0); - v_texcoord = texcoord; -})#"; - -inline const std::string TEXVERTSRC320 = R"#(#version 320 es -uniform mat3 proj; -in vec2 pos; -in vec2 texcoord; -out vec2 v_texcoord; - -void main() { - gl_Position = vec4(proj * vec3(pos, 1.0), 1.0); - v_texcoord = texcoord; -})#"; - -inline const std::string TEXFRAGSRCCM = -#include "CM.frag" - ; - -inline const std::string TEXFRAGSRCRGBA = R"#( -precision highp float; -varying vec2 v_texcoord; // is in 0-1 -uniform sampler2D tex; -uniform float alpha; - -uniform vec2 topLeft; -uniform vec2 fullSize; -uniform float radius; -uniform float roundingPower; - -uniform int discardOpaque; -uniform int discardAlpha; -uniform float discardAlphaValue; - -uniform int applyTint; -uniform vec3 tint; - -void main() { - - vec4 pixColor = texture2D(tex, v_texcoord); - - if (discardOpaque == 1 && pixColor[3] * alpha == 1.0) - discard; - - if (discardAlpha == 1 && pixColor[3] <= discardAlphaValue) - discard; - - if (applyTint == 1) { - pixColor[0] = pixColor[0] * tint[0]; - pixColor[1] = pixColor[1] * tint[1]; - pixColor[2] = pixColor[2] * tint[2]; - } - - if (radius > 0.0) { - )#" + - ROUNDED_SHADER_FUNC("pixColor") + R"#( - } - - gl_FragColor = pixColor * alpha; -})#"; - -inline const std::string TEXFRAGSRCRGBAPASSTHRU = R"#( -precision highp float; -varying vec2 v_texcoord; // is in 0-1 -uniform sampler2D tex; - -void main() { - gl_FragColor = texture2D(tex, v_texcoord); -})#"; - -inline const std::string TEXFRAGSRCRGBAMATTE = R"#( -precision highp float; -varying vec2 v_texcoord; // is in 0-1 -uniform sampler2D tex; -uniform sampler2D texMatte; - -void main() { - gl_FragColor = texture2D(tex, v_texcoord) * texture2D(texMatte, v_texcoord)[0]; // I know it only uses R, but matte should be black/white anyways. -})#"; - -inline const std::string TEXFRAGSRCRGBX = R"#( -precision highp float; -varying vec2 v_texcoord; -uniform sampler2D tex; -uniform float alpha; - -uniform vec2 topLeft; -uniform vec2 fullSize; -uniform float radius; -uniform float roundingPower; - -uniform int discardOpaque; -uniform int discardAlpha; -uniform int discardAlphaValue; - -uniform int applyTint; -uniform vec3 tint; - -void main() { - - if (discardOpaque == 1 && alpha == 1.0) - discard; - - vec4 pixColor = vec4(texture2D(tex, v_texcoord).rgb, 1.0); - - if (applyTint == 1) { - pixColor[0] = pixColor[0] * tint[0]; - pixColor[1] = pixColor[1] * tint[1]; - pixColor[2] = pixColor[2] * tint[2]; - } - - if (radius > 0.0) { - )#" + - ROUNDED_SHADER_FUNC("pixColor") + R"#( - } - - gl_FragColor = pixColor * alpha; -})#"; - -inline const std::string FRAGBLUR1 = R"#( -#version 100 -precision highp float; -varying highp vec2 v_texcoord; // is in 0-1 -uniform sampler2D tex; - -uniform float radius; -uniform vec2 halfpixel; -uniform int passes; -uniform float vibrancy; -uniform float vibrancy_darkness; - -// see http://alienryderflex.com/hsp.html -const float Pr = 0.299; -const float Pg = 0.587; -const float Pb = 0.114; - -// Y is "v" ( brightness ). X is "s" ( saturation ) -// see https://www.desmos.com/3d/a88652b9a4 -// Determines if high brightness or high saturation is more important -const float a = 0.93; -const float b = 0.11; -const float c = 0.66; // Determines the smoothness of the transition of unboosted to boosted colors -// - -// http://www.flong.com/archive/texts/code/shapers_circ/ -float doubleCircleSigmoid(float x, float a) { - a = clamp(a, 0.0, 1.0); - - float y = .0; - if (x <= a) { - y = a - sqrt(a * a - x * x); - } else { - y = a + sqrt(pow(1. - a, 2.) - pow(x - 1., 2.)); - } - return y; -} - -vec3 rgb2hsl(vec3 col) { - float red = col.r; - float green = col.g; - float blue = col.b; - - float minc = min(col.r, min(col.g, col.b)); - float maxc = max(col.r, max(col.g, col.b)); - float delta = maxc - minc; - - float lum = (minc + maxc) * 0.5; - float sat = 0.0; - float hue = 0.0; - - if (lum > 0.0 && lum < 1.0) { - float mul = (lum < 0.5) ? (lum) : (1.0 - lum); - sat = delta / (mul * 2.0); - } - - if (delta > 0.0) { - vec3 maxcVec = vec3(maxc); - vec3 masks = vec3(equal(maxcVec, col)) * vec3(notEqual(maxcVec, vec3(green, blue, red))); - vec3 adds = vec3(0.0, 2.0, 4.0) + vec3(green - blue, blue - red, red - green) / delta; - - hue += dot(adds, masks); - hue /= 6.0; - - if (hue < 0.0) - hue += 1.0; - } - - return vec3(hue, sat, lum); -} - -vec3 hsl2rgb(vec3 col) { - const float onethird = 1.0 / 3.0; - const float twothird = 2.0 / 3.0; - const float rcpsixth = 6.0; - - float hue = col.x; - float sat = col.y; - float lum = col.z; - - vec3 xt = vec3(0.0); - - if (hue < onethird) { - xt.r = rcpsixth * (onethird - hue); - xt.g = rcpsixth * hue; - xt.b = 0.0; - } else if (hue < twothird) { - xt.r = 0.0; - xt.g = rcpsixth * (twothird - hue); - xt.b = rcpsixth * (hue - onethird); - } else - xt = vec3(rcpsixth * (hue - twothird), 0.0, rcpsixth * (1.0 - hue)); - - xt = min(xt, 1.0); - - float sat2 = 2.0 * sat; - float satinv = 1.0 - sat; - float luminv = 1.0 - lum; - float lum2m1 = (2.0 * lum) - 1.0; - vec3 ct = (sat2 * xt) + satinv; - - vec3 rgb; - if (lum >= 0.5) - rgb = (luminv * ct) + lum2m1; - else - rgb = lum * ct; - - return rgb; -} - -void main() { - vec2 uv = v_texcoord * 2.0; - - vec4 sum = texture2D(tex, uv) * 4.0; - sum += texture2D(tex, uv - halfpixel.xy * radius); - sum += texture2D(tex, uv + halfpixel.xy * radius); - sum += texture2D(tex, uv + vec2(halfpixel.x, -halfpixel.y) * radius); - sum += texture2D(tex, uv - vec2(halfpixel.x, -halfpixel.y) * radius); - - vec4 color = sum / 8.0; - - if (vibrancy == 0.0) { - gl_FragColor = color; - } else { - // Invert it so that it correctly maps to the config setting - float vibrancy_darkness1 = 1.0 - vibrancy_darkness; - - // Decrease the RGB components based on their perceived brightness, to prevent visually dark colors from overblowing the rest. - vec3 hsl = rgb2hsl(color.rgb); - // Calculate perceived brightness, as not boost visually dark colors like deep blue as much as equally saturated yellow - float perceivedBrightness = doubleCircleSigmoid(sqrt(color.r * color.r * Pr + color.g * color.g * Pg + color.b * color.b * Pb), 0.8 * vibrancy_darkness1); - - float b1 = b * vibrancy_darkness1; - float boostBase = hsl[1] > 0.0 ? smoothstep(b1 - c * 0.5, b1 + c * 0.5, 1.0 - (pow(1.0 - hsl[1] * cos(a), 2.0) + pow(1.0 - perceivedBrightness * sin(a), 2.0))) : 0.0; - - float saturation = clamp(hsl[1] + (boostBase * vibrancy) / float(passes), 0.0, 1.0); - - vec3 newColor = hsl2rgb(vec3(hsl[0], saturation, hsl[2])); - - gl_FragColor = vec4(newColor, color[3]); - } -} -)#"; - -inline const std::string FRAGBLUR2 = R"#( -#version 100 -precision highp float; -varying highp vec2 v_texcoord; // is in 0-1 -uniform sampler2D tex; - -uniform float radius; -uniform vec2 halfpixel; - -void main() { - vec2 uv = v_texcoord / 2.0; - - vec4 sum = texture2D(tex, uv + vec2(-halfpixel.x * 2.0, 0.0) * radius); - - sum += texture2D(tex, uv + vec2(-halfpixel.x, halfpixel.y) * radius) * 2.0; - sum += texture2D(tex, uv + vec2(0.0, halfpixel.y * 2.0) * radius); - sum += texture2D(tex, uv + vec2(halfpixel.x, halfpixel.y) * radius) * 2.0; - sum += texture2D(tex, uv + vec2(halfpixel.x * 2.0, 0.0) * radius); - sum += texture2D(tex, uv + vec2(halfpixel.x, -halfpixel.y) * radius) * 2.0; - sum += texture2D(tex, uv + vec2(0.0, -halfpixel.y * 2.0) * radius); - sum += texture2D(tex, uv + vec2(-halfpixel.x, -halfpixel.y) * radius) * 2.0; - - gl_FragColor = sum / 12.0; -} -)#"; - -inline const std::string FRAGBLURPREPARE = R"#( -precision highp float; -varying vec2 v_texcoord; // is in 0-1 -uniform sampler2D tex; - -uniform float contrast; -uniform float brightness; - -float gain(float x, float k) { - float a = 0.5 * pow(2.0 * ((x < 0.5) ? x : 1.0 - x), k); - return (x < 0.5) ? a : 1.0 - a; -} - -void main() { - vec4 pixColor = texture2D(tex, v_texcoord); - - // contrast - if (contrast != 1.0) { - pixColor.r = gain(pixColor.r, contrast); - pixColor.g = gain(pixColor.g, contrast); - pixColor.b = gain(pixColor.b, contrast); - } - - // brightness - if (brightness > 1.0) { - pixColor.rgb *= brightness; - } - - gl_FragColor = pixColor; -} -)#"; - -inline const std::string FRAGBLURFINISH = R"#( -precision highp float; -varying vec2 v_texcoord; // is in 0-1 -uniform sampler2D tex; - -uniform float noise; -uniform float brightness; - -float hash(vec2 p) { - vec3 p3 = fract(vec3(p.xyx) * 1689.1984); - p3 += dot(p3, p3.yzx + 33.33); - return fract((p3.x + p3.y) * p3.z); -} - -void main() { - vec4 pixColor = texture2D(tex, v_texcoord); - - // noise - float noiseHash = hash(v_texcoord); - float noiseAmount = (mod(noiseHash, 1.0) - 0.5); - pixColor.rgb += noiseAmount * noise; - - // brightness - if (brightness < 1.0) { - pixColor.rgb *= brightness; - } - - gl_FragColor = pixColor; -} -)#"; - -inline const std::string TEXFRAGSRCEXT = R"#( -#extension GL_OES_EGL_image_external : require - -precision highp float; -varying vec2 v_texcoord; -uniform samplerExternalOES texture0; -uniform float alpha; - -uniform vec2 topLeft; -uniform vec2 fullSize; -uniform float radius; -uniform float roundingPower; - -uniform int discardOpaque; -uniform int discardAlpha; -uniform int discardAlphaValue; - -uniform int applyTint; -uniform vec3 tint; - -void main() { - - vec4 pixColor = texture2D(texture0, v_texcoord); - - if (discardOpaque == 1 && pixColor[3] * alpha == 1.0) - discard; - - if (applyTint == 1) { - pixColor[0] = pixColor[0] * tint[0]; - pixColor[1] = pixColor[1] * tint[1]; - pixColor[2] = pixColor[2] * tint[2]; - } - - if (radius > 0.0) { - )#" + - ROUNDED_SHADER_FUNC("pixColor") + R"#( - } - - gl_FragColor = pixColor * alpha; -} -)#"; - -static const std::string FRAGGLITCH = R"#( -precision highp float; -varying vec2 v_texcoord; -uniform sampler2D tex; -uniform float time; // quirk: time is set to 0 at the beginning, should be around 10 when crash. -uniform float distort; -uniform vec2 screenSize; - -float rand(float co) { - return fract(sin(dot(vec2(co, co), vec2(12.9898, 78.233))) * 43758.5453); -} - -float rand(vec2 co) { - return fract(sin(dot(co, vec2(12.9898, 78.233))) * 43758.5453); -} - -float noise(vec2 point) { - vec2 floored = floor(point); - vec2 fractal = fract(point); - fractal = fractal * fractal * (3.0 - 2.0 * fractal); - - float mixed = mix( - mix(rand(floored), rand(floored + vec2(1.0, 0.0)), fractal.x), - mix(rand(floored + vec2(0.0,1.0)), rand(floored + vec2(1.0,1.0)), fractal.x), fractal.y); - return mixed * mixed; -} - -void main() { - float ABERR_OFFSET = 4.0 * (distort / 5.5) * time; - float TEAR_AMOUNT = 9000.0 * (1.0 - (distort / 5.5)); - float TEAR_BANDS = 108.0 / 2.0 * (distort / 5.5) * 2.0; - float MELT_AMOUNT = (distort * 8.0) / screenSize.y; - - float NOISE = abs(mod(noise(v_texcoord) * distort * time * 2.771, 1.0)) * time / 10.0; - if (time < 2.0) - NOISE = 0.0; - - float offset = (mod(rand(floor(v_texcoord.y * TEAR_BANDS)) * 318.772 * time, 20.0) - 10.0) / TEAR_AMOUNT; - - vec2 blockOffset = vec2(((abs(mod(rand(floor(v_texcoord.x * 37.162)) * 721.43, 100.0))) - 50.0) / 200000.0 * pow(time, 3.0), - ((abs(mod(rand(floor(v_texcoord.y * 45.882)) * 733.923, 100.0))) - 50.0) / 200000.0 * pow(time, 3.0)); - if (time < 3.0) - blockOffset = vec2(0,0); - - float meltSeed = abs(mod(rand(floor(v_texcoord.x * screenSize.x * 17.719)) * 281.882, 1.0)); - if (meltSeed < 0.8) { - meltSeed = 0.0; - } else { - meltSeed *= 25.0 * NOISE; - } - float meltAmount = MELT_AMOUNT * meltSeed; - - vec2 pixCoord = vec2(v_texcoord.x + offset + NOISE * 3.0 / screenSize.x + blockOffset.x, v_texcoord.y - meltAmount + 0.02 * NOISE / screenSize.x + NOISE * 3.0 / screenSize.y + blockOffset.y); - - vec4 pixColor = texture2D(tex, pixCoord); - vec4 pixColorLeft = texture2D(tex, pixCoord + vec2(ABERR_OFFSET / screenSize.x, 0)); - vec4 pixColorRight = texture2D(tex, pixCoord + vec2(-ABERR_OFFSET / screenSize.x, 0)); - - pixColor[0] = pixColorLeft[0]; - pixColor[2] = pixColorRight[2]; - - pixColor[0] += distort / 90.0; - - gl_FragColor = pixColor; -} -)#"; diff --git a/src/render/shaders/glsl/CM.frag b/src/render/shaders/glsl/CM.frag new file mode 100644 index 000000000..369e9cf0f --- /dev/null +++ b/src/render/shaders/glsl/CM.frag @@ -0,0 +1,55 @@ +#version 300 es +//#extension GL_OES_EGL_image_external : require +#extension GL_ARB_shading_language_include : enable + +precision highp float; +in vec2 v_texcoord; +uniform sampler2D tex; +//uniform samplerExternalOES texture0; + +uniform int texType; // eTextureType: 0 - rgba, 1 - rgbx, 2 - ext +// uniform int skipCM; +uniform int sourceTF; // eTransferFunction +uniform int targetTF; // eTransferFunction +uniform mat4x2 sourcePrimaries; +uniform mat4x2 targetPrimaries; + +uniform float alpha; + +uniform int discardOpaque; +uniform int discardAlpha; +uniform float discardAlphaValue; + +uniform int applyTint; +uniform vec3 tint; + +#include "rounding.glsl" +#include "CM.glsl" + +layout(location = 0) out vec4 fragColor; +void main() { + vec4 pixColor; + if (texType == 1) + pixColor = vec4(texture(tex, v_texcoord).rgb, 1.0); +// else if (texType == 2) +// pixColor = texture(texture0, v_texcoord); + else // assume rgba + pixColor = texture(tex, v_texcoord); + + if (discardOpaque == 1 && pixColor[3] * alpha == 1.0) + discard; + + if (discardAlpha == 1 && pixColor[3] <= discardAlphaValue) + discard; + + // this shader shouldn't be used when skipCM == 1 + pixColor = doColorManagement(pixColor, sourceTF, sourcePrimaries, targetTF, targetPrimaries); + + if (applyTint == 1) + pixColor = vec4(pixColor.rgb * tint.rgb, pixColor[3]); + + if (radius > 0.0) + pixColor = rounding(pixColor); + + fragColor = pixColor * alpha; +} diff --git a/src/render/shaders/CM.frag b/src/render/shaders/glsl/CM.glsl similarity index 79% rename from src/render/shaders/CM.frag rename to src/render/shaders/glsl/CM.glsl index aa26f97d4..4cf2745c2 100644 --- a/src/render/shaders/CM.frag +++ b/src/render/shaders/glsl/CM.glsl @@ -1,37 +1,9 @@ -R"#( -#version 320 es -//#extension GL_OES_EGL_image_external : require - -precision highp float; -in vec2 v_texcoord; -uniform sampler2D tex; -//uniform samplerExternalOES texture0; - -uniform int texType; // eTextureType: 0 - rgba, 1 - rgbx, 2 - ext -uniform int sourceTF; // eTransferFunction -uniform int targetTF; // eTransferFunction -uniform mat4x2 sourcePrimaries; -uniform mat4x2 targetPrimaries; uniform float maxLuminance; uniform float dstMaxLuminance; uniform float dstRefLuminance; uniform float sdrSaturation; uniform float sdrBrightnessMultiplier; -uniform float alpha; - -uniform vec2 topLeft; -uniform vec2 fullSize; -uniform float radius; -uniform float roundingPower; - -uniform int discardOpaque; -uniform int discardAlpha; -uniform float discardAlphaValue; - -uniform int applyTint; -uniform vec3 tint; - //enum eTransferFunction #define CM_TRANSFER_FUNCTION_BT1886 1 #define CM_TRANSFER_FUNCTION_GAMMA22 2 @@ -78,31 +50,7 @@ uniform vec3 tint; #define HDR_MAX_LUMINANCE 10000.0 #define HLG_MAX_LUMINANCE 1000.0 -// smoothing constant for the edge: more = blurrier, but smoother -#define M_PI 3.1415926535897932384626433832795 #define M_E 2.718281828459045 -#define SMOOTHING_CONSTANT (M_PI / 5.34665792551) - -vec4 rounding(vec4 color) { - highp vec2 pixCoord = vec2(gl_FragCoord); - pixCoord -= topLeft + fullSize * 0.5; - pixCoord *= vec2(lessThan(pixCoord, vec2(0.0))) * -2.0 + 1.0; - pixCoord -= fullSize * 0.5 - radius; - pixCoord += vec2(1.0, 1.0) / fullSize; // center the pix dont make it top-left - - if (pixCoord.x + pixCoord.y > radius) { - float dist = pow(pow(pixCoord.x, roundingPower) + pow(pixCoord.y, roundingPower), 1.0/roundingPower); - - if (dist > radius + SMOOTHING_CONSTANT) - discard; - - float normalized = 1.0 - smoothstep(0.0, 1.0, (dist - radius + SMOOTHING_CONSTANT) / (SMOOTHING_CONSTANT * 2.0)); - - color *= normalized; - } - - return color; -} vec3 xy2xyz(vec2 xy) { if (xy.y == 0.0) @@ -391,50 +339,26 @@ vec4 tonemap(vec4 color, mat3 dstXYZ) { return vec4(fromLMS * toLinear(vec4(ICtCpPQInv * ICtCp, 1.0), CM_TRANSFER_FUNCTION_ST2084_PQ).rgb * HDR_MAX_LUMINANCE, color[3]); } -layout(location = 0) out vec4 fragColor; -void main() { - vec4 pixColor; - if (texType == 1) - pixColor = vec4(texture(tex, v_texcoord).rgb, 1.0); -// else if (texType == 2) -// pixColor = texture(texture0, v_texcoord); - else // assume rgba - pixColor = texture(tex, v_texcoord); - - if (discardOpaque == 1 && pixColor[3] * alpha == 1.0) - discard; - - if (discardAlpha == 1 && pixColor[3] <= discardAlphaValue) - discard; - - pixColor.rgb /= max(pixColor.a, 0.001); - pixColor.rgb = toLinearRGB(pixColor.rgb, sourceTF); - mat3 srcxyz = primaries2xyz(sourcePrimaries); - mat3 dstxyz; - - if (sourcePrimaries == targetPrimaries) - dstxyz = srcxyz; - else { - dstxyz = primaries2xyz(targetPrimaries); - pixColor = convertPrimaries(pixColor, srcxyz, sourcePrimaries[3], dstxyz, targetPrimaries[3]); - } - - pixColor = toNit(pixColor, sourceTF); - pixColor.rgb *= pixColor.a; - pixColor = tonemap(pixColor, dstxyz); - - if (sourceTF == CM_TRANSFER_FUNCTION_SRGB && targetTF == CM_TRANSFER_FUNCTION_ST2084_PQ) - pixColor = saturate(pixColor, srcxyz, sdrSaturation); - - pixColor *= sdrBrightnessMultiplier; - pixColor = fromLinearNit(pixColor, targetTF); - - if (applyTint == 1) - pixColor = vec4(pixColor.rgb * tint.rgb, pixColor[3]); - - if (radius > 0.0) - pixColor = rounding(pixColor); - - fragColor = pixColor * alpha; +vec4 doColorManagement(vec4 pixColor, int srcTF, mat4x2 srcPrimaries, int dstTF, mat4x2 dstPrimaries) { + pixColor.rgb /= max(pixColor.a, 0.001); + pixColor.rgb = toLinearRGB(pixColor.rgb, srcTF); + mat3 srcxyz = primaries2xyz(srcPrimaries); + mat3 dstxyz; + if (srcPrimaries == dstPrimaries) + dstxyz = srcxyz; + else { + dstxyz = primaries2xyz(dstPrimaries); + pixColor = convertPrimaries(pixColor, srcxyz, srcPrimaries[3], dstxyz, dstPrimaries[3]); + } + pixColor = toNit(pixColor, srcTF); + pixColor.rgb *= pixColor.a; + pixColor = tonemap(pixColor, dstxyz); + pixColor = fromLinearNit(pixColor, dstTF); + if (srcTF == CM_TRANSFER_FUNCTION_SRGB && dstTF == CM_TRANSFER_FUNCTION_ST2084_PQ) { + pixColor = saturate(pixColor, srcxyz, sdrSaturation); + pixColor.rgb /= pixColor.a; + pixColor.rgb *= sdrBrightnessMultiplier; + pixColor.rgb *= pixColor.a; + } + return pixColor; } -)#" diff --git a/src/render/shaders/glsl/blur1.frag b/src/render/shaders/glsl/blur1.frag new file mode 100644 index 000000000..dbabd6101 --- /dev/null +++ b/src/render/shaders/glsl/blur1.frag @@ -0,0 +1,141 @@ +#version 100 +precision highp float; +varying highp vec2 v_texcoord; // is in 0-1 +uniform sampler2D tex; + +uniform float radius; +uniform vec2 halfpixel; +uniform int passes; +uniform float vibrancy; +uniform float vibrancy_darkness; + +// see http://alienryderflex.com/hsp.html +const float Pr = 0.299; +const float Pg = 0.587; +const float Pb = 0.114; + +// Y is "v" ( brightness ). X is "s" ( saturation ) +// see https://www.desmos.com/3d/a88652b9a4 +// Determines if high brightness or high saturation is more important +const float a = 0.93; +const float b = 0.11; +const float c = 0.66; // Determines the smoothness of the transition of unboosted to boosted colors +// + +// http://www.flong.com/archive/texts/code/shapers_circ/ +float doubleCircleSigmoid(float x, float a) { + a = clamp(a, 0.0, 1.0); + + float y = .0; + if (x <= a) { + y = a - sqrt(a * a - x * x); + } else { + y = a + sqrt(pow(1. - a, 2.) - pow(x - 1., 2.)); + } + return y; +} + +vec3 rgb2hsl(vec3 col) { + float red = col.r; + float green = col.g; + float blue = col.b; + + float minc = min(col.r, min(col.g, col.b)); + float maxc = max(col.r, max(col.g, col.b)); + float delta = maxc - minc; + + float lum = (minc + maxc) * 0.5; + float sat = 0.0; + float hue = 0.0; + + if (lum > 0.0 && lum < 1.0) { + float mul = (lum < 0.5) ? (lum) : (1.0 - lum); + sat = delta / (mul * 2.0); + } + + if (delta > 0.0) { + vec3 maxcVec = vec3(maxc); + vec3 masks = vec3(equal(maxcVec, col)) * vec3(notEqual(maxcVec, vec3(green, blue, red))); + vec3 adds = vec3(0.0, 2.0, 4.0) + vec3(green - blue, blue - red, red - green) / delta; + + hue += dot(adds, masks); + hue /= 6.0; + + if (hue < 0.0) + hue += 1.0; + } + + return vec3(hue, sat, lum); +} + +vec3 hsl2rgb(vec3 col) { + const float onethird = 1.0 / 3.0; + const float twothird = 2.0 / 3.0; + const float rcpsixth = 6.0; + + float hue = col.x; + float sat = col.y; + float lum = col.z; + + vec3 xt = vec3(0.0); + + if (hue < onethird) { + xt.r = rcpsixth * (onethird - hue); + xt.g = rcpsixth * hue; + xt.b = 0.0; + } else if (hue < twothird) { + xt.r = 0.0; + xt.g = rcpsixth * (twothird - hue); + xt.b = rcpsixth * (hue - onethird); + } else + xt = vec3(rcpsixth * (hue - twothird), 0.0, rcpsixth * (1.0 - hue)); + + xt = min(xt, 1.0); + + float sat2 = 2.0 * sat; + float satinv = 1.0 - sat; + float luminv = 1.0 - lum; + float lum2m1 = (2.0 * lum) - 1.0; + vec3 ct = (sat2 * xt) + satinv; + + vec3 rgb; + if (lum >= 0.5) + rgb = (luminv * ct) + lum2m1; + else + rgb = lum * ct; + + return rgb; +} + +void main() { + vec2 uv = v_texcoord * 2.0; + + vec4 sum = texture2D(tex, uv) * 4.0; + sum += texture2D(tex, uv - halfpixel.xy * radius); + sum += texture2D(tex, uv + halfpixel.xy * radius); + sum += texture2D(tex, uv + vec2(halfpixel.x, -halfpixel.y) * radius); + sum += texture2D(tex, uv - vec2(halfpixel.x, -halfpixel.y) * radius); + + vec4 color = sum / 8.0; + + if (vibrancy == 0.0) { + gl_FragColor = color; + } else { + // Invert it so that it correctly maps to the config setting + float vibrancy_darkness1 = 1.0 - vibrancy_darkness; + + // Decrease the RGB components based on their perceived brightness, to prevent visually dark colors from overblowing the rest. + vec3 hsl = rgb2hsl(color.rgb); + // Calculate perceived brightness, as not boost visually dark colors like deep blue as much as equally saturated yellow + float perceivedBrightness = doubleCircleSigmoid(sqrt(color.r * color.r * Pr + color.g * color.g * Pg + color.b * color.b * Pb), 0.8 * vibrancy_darkness1); + + float b1 = b * vibrancy_darkness1; + float boostBase = hsl[1] > 0.0 ? smoothstep(b1 - c * 0.5, b1 + c * 0.5, 1.0 - (pow(1.0 - hsl[1] * cos(a), 2.0) + pow(1.0 - perceivedBrightness * sin(a), 2.0))) : 0.0; + + float saturation = clamp(hsl[1] + (boostBase * vibrancy) / float(passes), 0.0, 1.0); + + vec3 newColor = hsl2rgb(vec3(hsl[0], saturation, hsl[2])); + + gl_FragColor = vec4(newColor, color[3]); + } +} diff --git a/src/render/shaders/glsl/blur2.frag b/src/render/shaders/glsl/blur2.frag new file mode 100644 index 000000000..dfd8eeab6 --- /dev/null +++ b/src/render/shaders/glsl/blur2.frag @@ -0,0 +1,23 @@ +#version 100 +precision highp float; +varying highp vec2 v_texcoord; // is in 0-1 +uniform sampler2D tex; + +uniform float radius; +uniform vec2 halfpixel; + +void main() { + vec2 uv = v_texcoord / 2.0; + + vec4 sum = texture2D(tex, uv + vec2(-halfpixel.x * 2.0, 0.0) * radius); + + sum += texture2D(tex, uv + vec2(-halfpixel.x, halfpixel.y) * radius) * 2.0; + sum += texture2D(tex, uv + vec2(0.0, halfpixel.y * 2.0) * radius); + sum += texture2D(tex, uv + vec2(halfpixel.x, halfpixel.y) * radius) * 2.0; + sum += texture2D(tex, uv + vec2(halfpixel.x * 2.0, 0.0) * radius); + sum += texture2D(tex, uv + vec2(halfpixel.x, -halfpixel.y) * radius) * 2.0; + sum += texture2D(tex, uv + vec2(0.0, -halfpixel.y * 2.0) * radius); + sum += texture2D(tex, uv + vec2(-halfpixel.x, -halfpixel.y) * radius) * 2.0; + + gl_FragColor = sum / 12.0; +} diff --git a/src/render/shaders/glsl/blurfinish.frag b/src/render/shaders/glsl/blurfinish.frag new file mode 100644 index 000000000..6ab483378 --- /dev/null +++ b/src/render/shaders/glsl/blurfinish.frag @@ -0,0 +1,32 @@ +#version 300 es +#extension GL_ARB_shading_language_include : enable + +precision highp float; +in vec2 v_texcoord; // is in 0-1 +uniform sampler2D tex; + +uniform float noise; +uniform float brightness; + +float hash(vec2 p) { + vec3 p3 = fract(vec3(p.xyx) * 1689.1984); + p3 += dot(p3, p3.yzx + 33.33); + return fract((p3.x + p3.y) * p3.z); +} + +layout(location = 0) out vec4 fragColor; +void main() { + vec4 pixColor = texture(tex, v_texcoord); + + // noise + float noiseHash = hash(v_texcoord); + float noiseAmount = (mod(noiseHash, 1.0) - 0.5); + pixColor.rgb += noiseAmount * noise; + + // brightness + if (brightness < 1.0) { + pixColor.rgb *= brightness; + } + + fragColor = pixColor; +} diff --git a/src/render/shaders/glsl/blurfinish_legacy.frag b/src/render/shaders/glsl/blurfinish_legacy.frag new file mode 100644 index 000000000..2a7ebca1c --- /dev/null +++ b/src/render/shaders/glsl/blurfinish_legacy.frag @@ -0,0 +1,28 @@ +precision highp float; +varying vec2 v_texcoord; // is in 0-1 +uniform sampler2D tex; + +uniform float noise; +uniform float brightness; + +float hash(vec2 p) { + vec3 p3 = fract(vec3(p.xyx) * 1689.1984); + p3 += dot(p3, p3.yzx + 33.33); + return fract((p3.x + p3.y) * p3.z); +} + +void main() { + vec4 pixColor = texture2D(tex, v_texcoord); + + // noise + float noiseHash = hash(v_texcoord); + float noiseAmount = (mod(noiseHash, 1.0) - 0.5); + pixColor.rgb += noiseAmount * noise; + + // brightness + if (brightness < 1.0) { + pixColor.rgb *= brightness; + } + + gl_FragColor = pixColor; +} diff --git a/src/render/shaders/glsl/blurprepare.frag b/src/render/shaders/glsl/blurprepare.frag new file mode 100644 index 000000000..0be2d53ac --- /dev/null +++ b/src/render/shaders/glsl/blurprepare.frag @@ -0,0 +1,58 @@ +#version 300 es +#extension GL_ARB_shading_language_include : enable + +precision highp float; +in vec2 v_texcoord; // is in 0-1 +uniform sampler2D tex; + +uniform float contrast; +uniform float brightness; + +uniform int skipCM; +uniform int sourceTF; // eTransferFunction +uniform int targetTF; // eTransferFunction +uniform mat4x2 sourcePrimaries; +uniform mat4x2 targetPrimaries; + +#include "CM.glsl" + +float gain(float x, float k) { + float a = 0.5 * pow(2.0 * ((x < 0.5) ? x : 1.0 - x), k); + return (x < 0.5) ? a : 1.0 - a; +} + +layout(location = 0) out vec4 fragColor; +void main() { + vec4 pixColor = texture(tex, v_texcoord); + + if (skipCM == 0) { + if (sourceTF == CM_TRANSFER_FUNCTION_ST2084_PQ) { + pixColor.rgb /= sdrBrightnessMultiplier; + } + pixColor.rgb = toLinearRGB(pixColor.rgb, sourceTF); + mat3 srcxyz = primaries2xyz(sourcePrimaries); + mat3 dstxyz; + if (sourcePrimaries == targetPrimaries) + dstxyz = srcxyz; + else { + dstxyz = primaries2xyz(targetPrimaries); + pixColor = convertPrimaries(pixColor, srcxyz, sourcePrimaries[3], dstxyz, targetPrimaries[3]); + } + pixColor = toNit(pixColor, sourceTF); + pixColor = fromLinearNit(pixColor, targetTF); + } + + // contrast + if (contrast != 1.0) { + pixColor.r = gain(pixColor.r, contrast); + pixColor.g = gain(pixColor.g, contrast); + pixColor.b = gain(pixColor.b, contrast); + } + + // brightness + if (brightness > 1.0) { + pixColor.rgb *= brightness; + } + + fragColor = pixColor; +} diff --git a/src/render/shaders/glsl/blurprepare_legacy.frag b/src/render/shaders/glsl/blurprepare_legacy.frag new file mode 100644 index 000000000..2df933d5d --- /dev/null +++ b/src/render/shaders/glsl/blurprepare_legacy.frag @@ -0,0 +1,29 @@ +precision highp float; +varying vec2 v_texcoord; // is in 0-1 +uniform sampler2D tex; + +uniform float contrast; +uniform float brightness; + +float gain(float x, float k) { + float a = 0.5 * pow(2.0 * ((x < 0.5) ? x : 1.0 - x), k); + return (x < 0.5) ? a : 1.0 - a; +} + +void main() { + vec4 pixColor = texture2D(tex, v_texcoord); + + // contrast + if (contrast != 1.0) { + pixColor.r = gain(pixColor.r, contrast); + pixColor.g = gain(pixColor.g, contrast); + pixColor.b = gain(pixColor.b, contrast); + } + + // brightness + if (brightness > 1.0) { + pixColor.rgb *= brightness; + } + + gl_FragColor = pixColor; +} diff --git a/src/render/shaders/glsl/border.frag b/src/render/shaders/glsl/border.frag new file mode 100644 index 000000000..68541e145 --- /dev/null +++ b/src/render/shaders/glsl/border.frag @@ -0,0 +1,183 @@ +#version 300 es +#extension GL_ARB_shading_language_include : enable + +precision highp float; +in vec2 v_texcoord; + +uniform int skipCM; +uniform int sourceTF; // eTransferFunction +uniform int targetTF; // eTransferFunction +uniform mat4x2 sourcePrimaries; +uniform mat4x2 targetPrimaries; + +uniform vec2 fullSizeUntransformed; +uniform float radiusOuter; +uniform float thick; + +// Gradients are in OkLabA!!!! {l, a, b, alpha} +uniform vec4 gradient[10]; +uniform vec4 gradient2[10]; +uniform int gradientLength; +uniform int gradient2Length; +uniform float angle; +uniform float angle2; +uniform float gradientLerp; +uniform float alpha; + +#include "rounding.glsl" +#include "CM.glsl" + +vec4 okLabAToSrgb(vec4 lab) { + float l = pow(lab[0] + lab[1] * 0.3963377774 + lab[2] * 0.2158037573, 3.0); + float m = pow(lab[0] + lab[1] * (-0.1055613458) + lab[2] * (-0.0638541728), 3.0); + float s = pow(lab[0] + lab[1] * (-0.0894841775) + lab[2] * (-1.2914855480), 3.0); + + return vec4(fromLinearRGB( + vec3( + l * 4.0767416621 + m * -3.3077115913 + s * 0.2309699292, + l * (-1.2684380046) + m * 2.6097574011 + s * (-0.3413193965), + l * (-0.0041960863) + m * (-0.7034186147) + s * 1.7076147010 + ), CM_TRANSFER_FUNCTION_SRGB + ), lab[3]); +} + +vec4 getOkColorForCoordArray1(vec2 normalizedCoord) { + if (gradientLength < 2) + return gradient[0]; + + float finalAng = 0.0; + + if (angle > 4.71 /* 270 deg */) { + normalizedCoord[1] = 1.0 - normalizedCoord[1]; + finalAng = 6.28 - angle; + } else if (angle > 3.14 /* 180 deg */) { + normalizedCoord[0] = 1.0 - normalizedCoord[0]; + normalizedCoord[1] = 1.0 - normalizedCoord[1]; + finalAng = angle - 3.14; + } else if (angle > 1.57 /* 90 deg */) { + normalizedCoord[0] = 1.0 - normalizedCoord[0]; + finalAng = 3.14 - angle; + } else { + finalAng = angle; + } + + float sine = sin(finalAng); + + float progress = (normalizedCoord[1] * sine + normalizedCoord[0] * (1.0 - sine)) * float(gradientLength - 1); + int bottom = int(floor(progress)); + int top = bottom + 1; + + return gradient[top] * (progress - float(bottom)) + gradient[bottom] * (float(top) - progress); +} + +vec4 getOkColorForCoordArray2(vec2 normalizedCoord) { + if (gradient2Length < 2) + return gradient2[0]; + + float finalAng = 0.0; + + if (angle2 > 4.71 /* 270 deg */) { + normalizedCoord[1] = 1.0 - normalizedCoord[1]; + finalAng = 6.28 - angle; + } else if (angle2 > 3.14 /* 180 deg */) { + normalizedCoord[0] = 1.0 - normalizedCoord[0]; + normalizedCoord[1] = 1.0 - normalizedCoord[1]; + finalAng = angle - 3.14; + } else if (angle2 > 1.57 /* 90 deg */) { + normalizedCoord[0] = 1.0 - normalizedCoord[0]; + finalAng = 3.14 - angle2; + } else { + finalAng = angle2; + } + + float sine = sin(finalAng); + + float progress = (normalizedCoord[1] * sine + normalizedCoord[0] * (1.0 - sine)) * float(gradient2Length - 1); + int bottom = int(floor(progress)); + int top = bottom + 1; + + return gradient2[top] * (progress - float(bottom)) + gradient2[bottom] * (float(top) - progress); +} + +vec4 getColorForCoord(vec2 normalizedCoord) { + vec4 result1 = getOkColorForCoordArray1(normalizedCoord); + + if (gradient2Length <= 0) + return okLabAToSrgb(result1); + + vec4 result2 = getOkColorForCoordArray2(normalizedCoord); + + return okLabAToSrgb(mix(result1, result2, gradientLerp)); +} + +layout(location = 0) out vec4 fragColor; +void main() { + highp vec2 pixCoord = vec2(gl_FragCoord); + highp vec2 pixCoordOuter = pixCoord; + highp vec2 originalPixCoord = v_texcoord; + originalPixCoord *= fullSizeUntransformed; + float additionalAlpha = 1.0; + + vec4 pixColor = vec4(1.0, 1.0, 1.0, 1.0); + + bool done = false; + + pixCoord -= topLeft + fullSize * 0.5; + pixCoord *= vec2(lessThan(pixCoord, vec2(0.0))) * -2.0 + 1.0; + pixCoordOuter = pixCoord; + pixCoord -= fullSize * 0.5 - radius; + pixCoordOuter -= fullSize * 0.5 - radiusOuter; + + // center the pixes dont make it top-left + pixCoord += vec2(1.0, 1.0) / fullSize; + pixCoordOuter += vec2(1.0, 1.0) / fullSize; + + if (min(pixCoord.x, pixCoord.y) > 0.0 && radius > 0.0) { + float dist = pow(pow(pixCoord.x,roundingPower)+pow(pixCoord.y,roundingPower),1.0/roundingPower); + float distOuter = pow(pow(pixCoordOuter.x,roundingPower)+pow(pixCoordOuter.y,roundingPower),1.0/roundingPower); + float h = (thick / 2.0); + + if (dist < radius - h) { + // lower + float normalized = smoothstep(0.0, 1.0, (dist - radius + thick + SMOOTHING_CONSTANT) / (SMOOTHING_CONSTANT * 2.0)); + additionalAlpha *= normalized; + done = true; + } else if (min(pixCoordOuter.x, pixCoordOuter.y) > 0.0) { + // higher + float normalized = 1.0 - smoothstep(0.0, 1.0, (distOuter - radiusOuter + SMOOTHING_CONSTANT) / (SMOOTHING_CONSTANT * 2.0)); + additionalAlpha *= normalized; + done = true; + } else if (distOuter < radiusOuter - h) { + additionalAlpha = 1.0; + done = true; + } + } + + // now check for other shit + if (!done) { + // distance to all straight bb borders + float distanceT = originalPixCoord[1]; + float distanceB = fullSizeUntransformed[1] - originalPixCoord[1]; + float distanceL = originalPixCoord[0]; + float distanceR = fullSizeUntransformed[0] - originalPixCoord[0]; + + // get the smallest + float smallest = min(min(distanceT, distanceB), min(distanceL, distanceR)); + + if (smallest > thick) + discard; + } + + if (additionalAlpha == 0.0) + discard; + + pixColor = getColorForCoord(v_texcoord); + pixColor.rgb *= pixColor[3]; + + if (skipCM == 0) + pixColor = doColorManagement(pixColor, sourceTF, sourcePrimaries, targetTF, targetPrimaries); + + pixColor *= alpha * additionalAlpha; + + fragColor = pixColor; +} diff --git a/src/render/shaders/Border.hpp b/src/render/shaders/glsl/border_legacy.frag similarity index 92% rename from src/render/shaders/Border.hpp rename to src/render/shaders/glsl/border_legacy.frag index 3b9a91f08..39842be5c 100644 --- a/src/render/shaders/Border.hpp +++ b/src/render/shaders/glsl/border_legacy.frag @@ -1,21 +1,11 @@ -#pragma once +#extension GL_ARB_shading_language_include : enable -#include -#include -#include "SharedValues.hpp" - -// makes a stencil without corners -inline const std::string FRAGBORDER1 = R"#( precision highp float; varying vec4 v_color; varying vec2 v_texcoord; -uniform vec2 topLeft; -uniform vec2 fullSize; uniform vec2 fullSizeUntransformed; -uniform float radius; uniform float radiusOuter; -uniform float roundingPower; uniform float thick; // Gradients are in OkLabA!!!! {l, a, b, alpha} @@ -28,6 +18,8 @@ uniform float angle2; uniform float gradientLerp; uniform float alpha; +#include "rounding.glsl" + float linearToGamma(float x) { return x >= 0.0031308 ? 1.055 * pow(x, 0.416666666) - 0.055 : 12.92 * x; } @@ -135,13 +127,9 @@ void main() { pixCoordOuter += vec2(1.0, 1.0) / fullSize; if (min(pixCoord.x, pixCoord.y) > 0.0 && radius > 0.0) { - // smoothing constant for the edge: more = blurrier, but smoother - const float SMOOTHING_CONSTANT = )#" + - std::format("{:.7f}", SHADER_ROUNDED_SMOOTHING_FACTOR) + R"#(; - float dist = pow(pow(pixCoord.x,roundingPower)+pow(pixCoord.y,roundingPower),1.0/roundingPower); float distOuter = pow(pow(pixCoordOuter.x,roundingPower)+pow(pixCoordOuter.y,roundingPower),1.0/roundingPower); - float h = (thick / 2.0); + float h = (thick / 2.0); if (dist < radius - h) { // lower @@ -184,4 +172,3 @@ void main() { gl_FragColor = pixColor; } -)#"; diff --git a/src/render/shaders/glsl/ext.frag b/src/render/shaders/glsl/ext.frag new file mode 100644 index 000000000..3b71f59c6 --- /dev/null +++ b/src/render/shaders/glsl/ext.frag @@ -0,0 +1,35 @@ +#extension GL_ARB_shading_language_include : enable +#extension GL_OES_EGL_image_external : require + +precision highp float; +varying vec2 v_texcoord; +uniform samplerExternalOES texture0; +uniform float alpha; + +#include "rounding.glsl" + +uniform int discardOpaque; +uniform int discardAlpha; +uniform int discardAlphaValue; + +uniform int applyTint; +uniform vec3 tint; + +void main() { + + vec4 pixColor = texture2D(texture0, v_texcoord); + + if (discardOpaque == 1 && pixColor[3] * alpha == 1.0) + discard; + + if (applyTint == 1) { + pixColor[0] = pixColor[0] * tint[0]; + pixColor[1] = pixColor[1] * tint[1]; + pixColor[2] = pixColor[2] * tint[2]; + } + + if (radius > 0.0) + pixColor = rounding(pixColor); + + gl_FragColor = pixColor * alpha; +} diff --git a/src/render/shaders/glsl/glitch.frag b/src/render/shaders/glsl/glitch.frag new file mode 100644 index 000000000..f1dc121e8 --- /dev/null +++ b/src/render/shaders/glsl/glitch.frag @@ -0,0 +1,64 @@ +precision highp float; +varying vec2 v_texcoord; +uniform sampler2D tex; +uniform float time; // quirk: time is set to 0 at the beginning, should be around 10 when crash. +uniform float distort; +uniform vec2 screenSize; + +float rand(float co) { + return fract(sin(dot(vec2(co, co), vec2(12.9898, 78.233))) * 43758.5453); +} + +float rand(vec2 co) { + return fract(sin(dot(co, vec2(12.9898, 78.233))) * 43758.5453); +} + +float noise(vec2 point) { + vec2 floored = floor(point); + vec2 fractal = fract(point); + fractal = fractal * fractal * (3.0 - 2.0 * fractal); + + float mixed = mix( + mix(rand(floored), rand(floored + vec2(1.0, 0.0)), fractal.x), + mix(rand(floored + vec2(0.0,1.0)), rand(floored + vec2(1.0,1.0)), fractal.x), fractal.y); + return mixed * mixed; +} + +void main() { + float ABERR_OFFSET = 4.0 * (distort / 5.5) * time; + float TEAR_AMOUNT = 9000.0 * (1.0 - (distort / 5.5)); + float TEAR_BANDS = 108.0 / 2.0 * (distort / 5.5) * 2.0; + float MELT_AMOUNT = (distort * 8.0) / screenSize.y; + + float NOISE = abs(mod(noise(v_texcoord) * distort * time * 2.771, 1.0)) * time / 10.0; + if (time < 2.0) + NOISE = 0.0; + + float offset = (mod(rand(floor(v_texcoord.y * TEAR_BANDS)) * 318.772 * time, 20.0) - 10.0) / TEAR_AMOUNT; + + vec2 blockOffset = vec2(((abs(mod(rand(floor(v_texcoord.x * 37.162)) * 721.43, 100.0))) - 50.0) / 200000.0 * pow(time, 3.0), + ((abs(mod(rand(floor(v_texcoord.y * 45.882)) * 733.923, 100.0))) - 50.0) / 200000.0 * pow(time, 3.0)); + if (time < 3.0) + blockOffset = vec2(0,0); + + float meltSeed = abs(mod(rand(floor(v_texcoord.x * screenSize.x * 17.719)) * 281.882, 1.0)); + if (meltSeed < 0.8) { + meltSeed = 0.0; + } else { + meltSeed *= 25.0 * NOISE; + } + float meltAmount = MELT_AMOUNT * meltSeed; + + vec2 pixCoord = vec2(v_texcoord.x + offset + NOISE * 3.0 / screenSize.x + blockOffset.x, v_texcoord.y - meltAmount + 0.02 * NOISE / screenSize.x + NOISE * 3.0 / screenSize.y + blockOffset.y); + + vec4 pixColor = texture2D(tex, pixCoord); + vec4 pixColorLeft = texture2D(tex, pixCoord + vec2(ABERR_OFFSET / screenSize.x, 0)); + vec4 pixColorRight = texture2D(tex, pixCoord + vec2(-ABERR_OFFSET / screenSize.x, 0)); + + pixColor[0] = pixColorLeft[0]; + pixColor[2] = pixColorRight[2]; + + pixColor[0] += distort / 90.0; + + gl_FragColor = pixColor; +} diff --git a/src/render/shaders/glsl/passthru.frag b/src/render/shaders/glsl/passthru.frag new file mode 100644 index 000000000..532b5525c --- /dev/null +++ b/src/render/shaders/glsl/passthru.frag @@ -0,0 +1,7 @@ +precision highp float; +varying vec2 v_texcoord; // is in 0-1 +uniform sampler2D tex; + +void main() { + gl_FragColor = texture2D(tex, v_texcoord); +} diff --git a/src/render/shaders/glsl/quad.frag b/src/render/shaders/glsl/quad.frag new file mode 100644 index 000000000..303d1a818 --- /dev/null +++ b/src/render/shaders/glsl/quad.frag @@ -0,0 +1,14 @@ +#extension GL_ARB_shading_language_include : enable +precision highp float; +varying vec4 v_color; + +#include "rounding.glsl" + +void main() { + vec4 pixColor = v_color; + + if (radius > 0.0) + pixColor = rounding(pixColor); + + gl_FragColor = pixColor; +} diff --git a/src/render/shaders/glsl/rgba.frag b/src/render/shaders/glsl/rgba.frag new file mode 100644 index 000000000..ac2d237d1 --- /dev/null +++ b/src/render/shaders/glsl/rgba.frag @@ -0,0 +1,36 @@ +#extension GL_ARB_shading_language_include : enable +precision highp float; +varying vec2 v_texcoord; // is in 0-1 +uniform sampler2D tex; +uniform float alpha; + +#include "rounding.glsl" + +uniform int discardOpaque; +uniform int discardAlpha; +uniform float discardAlphaValue; + +uniform int applyTint; +uniform vec3 tint; + +void main() { + + vec4 pixColor = texture2D(tex, v_texcoord); + + if (discardOpaque == 1 && pixColor[3] * alpha == 1.0) + discard; + + if (discardAlpha == 1 && pixColor[3] <= discardAlphaValue) + discard; + + if (applyTint == 1) { + pixColor[0] = pixColor[0] * tint[0]; + pixColor[1] = pixColor[1] * tint[1]; + pixColor[2] = pixColor[2] * tint[2]; + } + + if (radius > 0.0) + pixColor = rounding(pixColor); + + gl_FragColor = pixColor * alpha; +} diff --git a/src/render/shaders/glsl/rgbamatte.frag b/src/render/shaders/glsl/rgbamatte.frag new file mode 100644 index 000000000..618e495fe --- /dev/null +++ b/src/render/shaders/glsl/rgbamatte.frag @@ -0,0 +1,8 @@ +precision highp float; +varying vec2 v_texcoord; // is in 0-1 +uniform sampler2D tex; +uniform sampler2D texMatte; + +void main() { + gl_FragColor = texture2D(tex, v_texcoord) * texture2D(texMatte, v_texcoord)[0]; // I know it only uses R, but matte should be black/white anyways. +} diff --git a/src/render/shaders/glsl/rgbx.frag b/src/render/shaders/glsl/rgbx.frag new file mode 100644 index 000000000..2a2aad63f --- /dev/null +++ b/src/render/shaders/glsl/rgbx.frag @@ -0,0 +1,33 @@ +#extension GL_ARB_shading_language_include : enable +precision highp float; +varying vec2 v_texcoord; +uniform sampler2D tex; +uniform float alpha; + +#include "rounding.glsl" + +uniform int discardOpaque; +uniform int discardAlpha; +uniform int discardAlphaValue; + +uniform int applyTint; +uniform vec3 tint; + +void main() { + + if (discardOpaque == 1 && alpha == 1.0) + discard; + + vec4 pixColor = vec4(texture2D(tex, v_texcoord).rgb, 1.0); + + if (applyTint == 1) { + pixColor[0] = pixColor[0] * tint[0]; + pixColor[1] = pixColor[1] * tint[1]; + pixColor[2] = pixColor[2] * tint[2]; + } + + if (radius > 0.0) + pixColor = rounding(pixColor); + + gl_FragColor = pixColor * alpha; +} diff --git a/src/render/shaders/glsl/rounding.glsl b/src/render/shaders/glsl/rounding.glsl new file mode 100644 index 000000000..cae34465f --- /dev/null +++ b/src/render/shaders/glsl/rounding.glsl @@ -0,0 +1,29 @@ +// smoothing constant for the edge: more = blurrier, but smoother +#define M_PI 3.1415926535897932384626433832795 +#define SMOOTHING_CONSTANT (M_PI / 5.34665792551) + +uniform float radius; +uniform float roundingPower; +uniform vec2 topLeft; +uniform vec2 fullSize; + +vec4 rounding(vec4 color) { + vec2 pixCoord = vec2(gl_FragCoord); + pixCoord -= topLeft + fullSize * 0.5; + pixCoord *= vec2(lessThan(pixCoord, vec2(0.0))) * -2.0 + 1.0; + pixCoord -= fullSize * 0.5 - radius; + pixCoord += vec2(1.0, 1.0) / fullSize; // center the pix dont make it top-left + + if (pixCoord.x + pixCoord.y > radius) { + float dist = pow(pow(pixCoord.x, roundingPower) + pow(pixCoord.y, roundingPower), 1.0/roundingPower); + + if (dist > radius + SMOOTHING_CONSTANT) + discard; + + float normalized = 1.0 - smoothstep(0.0, 1.0, (dist - radius + SMOOTHING_CONSTANT) / (SMOOTHING_CONSTANT * 2.0)); + + color *= normalized; + } + + return color; +} diff --git a/src/render/shaders/glsl/shadow.frag b/src/render/shaders/glsl/shadow.frag new file mode 100644 index 000000000..7a930f965 --- /dev/null +++ b/src/render/shaders/glsl/shadow.frag @@ -0,0 +1,100 @@ +#version 300 es +#extension GL_ARB_shading_language_include : enable + +precision highp float; +in vec4 v_color; +in vec2 v_texcoord; + +uniform int skipCM; +uniform int sourceTF; // eTransferFunction +uniform int targetTF; // eTransferFunction +uniform mat4x2 sourcePrimaries; +uniform mat4x2 targetPrimaries; + +uniform vec2 topLeft; +uniform vec2 bottomRight; +uniform vec2 fullSize; +uniform float radius; +uniform float roundingPower; +uniform float range; +uniform float shadowPower; + +#include "CM.glsl" + +float pixAlphaRoundedDistance(float distanceToCorner) { + if (distanceToCorner > radius) { + return 0.0; + } + + if (distanceToCorner > radius - range) { + return pow((range - (distanceToCorner - radius + range)) / range, shadowPower); // i think? + } + + return 1.0; +} + +float modifiedLength(vec2 a) { + return pow(pow(abs(a.x),roundingPower)+pow(abs(a.y),roundingPower),1.0/roundingPower); +} + +layout(location = 0) out vec4 fragColor; +void main() { + + vec4 pixColor = v_color; + float originalAlpha = pixColor[3]; + + bool done = false; + + vec2 pixCoord = fullSize * v_texcoord; + + // ok, now we check the distance to a border. + + if (pixCoord[0] < topLeft[0]) { + if (pixCoord[1] < topLeft[1]) { + // top left + pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(modifiedLength(pixCoord - topLeft)); + done = true; + } else if (pixCoord[1] > bottomRight[1]) { + // bottom left + pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(modifiedLength(pixCoord - vec2(topLeft[0], bottomRight[1]))); + done = true; + } + } else if (pixCoord[0] > bottomRight[0]) { + if (pixCoord[1] < topLeft[1]) { + // top right + pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(modifiedLength(pixCoord - vec2(bottomRight[0], topLeft[1]))); + done = true; + } else if (pixCoord[1] > bottomRight[1]) { + // bottom right + pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(modifiedLength(pixCoord - bottomRight)); + done = true; + } + } + + if (!done) { + // distance to all straight bb borders + float distanceT = pixCoord[1]; + float distanceB = fullSize[1] - pixCoord[1]; + float distanceL = pixCoord[0]; + float distanceR = fullSize[0] - pixCoord[0]; + + // get the smallest + float smallest = min(min(distanceT, distanceB), min(distanceL, distanceR)); + + if (smallest < range) { + pixColor[3] = pixColor[3] * pow((smallest / range), shadowPower); + } + } + + if (pixColor[3] == 0.0) { + discard; return; + } + + // premultiply + pixColor.rgb *= pixColor[3]; + + if (skipCM == 0) + pixColor = doColorManagement(pixColor, sourceTF, sourcePrimaries, targetTF, targetPrimaries); + + fragColor = pixColor; +} \ No newline at end of file diff --git a/src/render/shaders/Shadow.hpp b/src/render/shaders/glsl/shadow_legacy.frag similarity index 96% rename from src/render/shaders/Shadow.hpp rename to src/render/shaders/glsl/shadow_legacy.frag index c04d4bf32..bf929e639 100644 --- a/src/render/shaders/Shadow.hpp +++ b/src/render/shaders/glsl/shadow_legacy.frag @@ -1,8 +1,4 @@ -#pragma once - -#include - -inline const std::string FRAGSHADOW = R"#( +#extension GL_ARB_shading_language_include : enable precision highp float; varying vec4 v_color; varying vec2 v_texcoord; @@ -87,4 +83,4 @@ void main() { pixColor.rgb *= pixColor[3]; gl_FragColor = pixColor; -})#"; +} diff --git a/src/render/shaders/glsl/tex.vert b/src/render/shaders/glsl/tex.vert new file mode 100644 index 000000000..6ede6a8e2 --- /dev/null +++ b/src/render/shaders/glsl/tex.vert @@ -0,0 +1,15 @@ +uniform mat3 proj; +uniform vec4 color; +attribute vec2 pos; +attribute vec2 texcoord; +attribute vec2 texcoordMatte; +varying vec4 v_color; +varying vec2 v_texcoord; +varying vec2 v_texcoordMatte; + +void main() { + gl_Position = vec4(proj * vec3(pos, 1.0), 1.0); + v_color = color; + v_texcoord = texcoord; + v_texcoordMatte = texcoordMatte; +} \ No newline at end of file diff --git a/src/render/shaders/glsl/tex300.vert b/src/render/shaders/glsl/tex300.vert new file mode 100644 index 000000000..f9f129986 --- /dev/null +++ b/src/render/shaders/glsl/tex300.vert @@ -0,0 +1,17 @@ +#version 300 es + +uniform mat3 proj; +uniform vec4 color; +in vec2 pos; +in vec2 texcoord; +in vec2 texcoordMatte; +out vec4 v_color; +out vec2 v_texcoord; +out vec2 v_texcoordMatte; + +void main() { + gl_Position = vec4(proj * vec3(pos, 1.0), 1.0); + v_color = color; + v_texcoord = texcoord; + v_texcoordMatte = texcoordMatte; +} diff --git a/src/render/shaders/glsl/tex320.vert b/src/render/shaders/glsl/tex320.vert new file mode 100644 index 000000000..309bc02b6 --- /dev/null +++ b/src/render/shaders/glsl/tex320.vert @@ -0,0 +1,17 @@ +#version 320 es + +uniform mat3 proj; +uniform vec4 color; +in vec2 pos; +in vec2 texcoord; +in vec2 texcoordMatte; +out vec4 v_color; +out vec2 v_texcoord; +out vec2 v_texcoordMatte; + +void main() { + gl_Position = vec4(proj * vec3(pos, 1.0), 1.0); + v_color = color; + v_texcoord = texcoord; + v_texcoordMatte = texcoordMatte; +}