renderer: shader variants refactor (#13434)
Part 0 of renderer reworks.
This commit is contained in:
parent
8685fd7b0c
commit
a5858018d8
62 changed files with 1952 additions and 1472 deletions
|
|
@ -125,6 +125,7 @@ find_package(Threads REQUIRED)
|
||||||
|
|
||||||
set(GLES_VERSION "GLES3")
|
set(GLES_VERSION "GLES3")
|
||||||
find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION})
|
find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION})
|
||||||
|
find_package(glslang CONFIG REQUIRED)
|
||||||
|
|
||||||
set(AQUAMARINE_MINIMUM_VERSION 0.9.3)
|
set(AQUAMARINE_MINIMUM_VERSION 0.9.3)
|
||||||
set(HYPRLANG_MINIMUM_VERSION 0.6.7)
|
set(HYPRLANG_MINIMUM_VERSION 0.6.7)
|
||||||
|
|
@ -479,9 +480,9 @@ function(protocolWayland)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
if(TARGET OpenGL::GL)
|
if(TARGET OpenGL::GL)
|
||||||
target_link_libraries(hyprland_lib PUBLIC OpenGL::EGL OpenGL::GL Threads::Threads)
|
target_link_libraries(hyprland_lib PUBLIC OpenGL::EGL OpenGL::GL glslang::glslang glslang::glslang-default-resource-limits glslang::SPIRV Threads::Threads)
|
||||||
else()
|
else()
|
||||||
target_link_libraries(hyprland_lib PUBLIC OpenGL::EGL OpenGL::GLES3 Threads::Threads)
|
target_link_libraries(hyprland_lib PUBLIC OpenGL::EGL OpenGL::GLES3 glslang::glslang glslang::glslang-default-resource-limits glslang::SPIRV Threads::Threads)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
pkg_check_modules(hyprland_protocols_dep hyprland-protocols>=0.6.4)
|
pkg_check_modules(hyprland_protocols_dep hyprland-protocols>=0.6.4)
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
epoll-shim,
|
epoll-shim,
|
||||||
git,
|
git,
|
||||||
glaze-hyprland,
|
glaze-hyprland,
|
||||||
|
glslang,
|
||||||
gtest,
|
gtest,
|
||||||
hyprcursor,
|
hyprcursor,
|
||||||
hyprgraphics,
|
hyprgraphics,
|
||||||
|
|
@ -173,6 +174,7 @@ customStdenv.mkDerivation (finalAttrs: {
|
||||||
cairo
|
cairo
|
||||||
git
|
git
|
||||||
glaze-hyprland
|
glaze-hyprland
|
||||||
|
glslang
|
||||||
gtest
|
gtest
|
||||||
hyprcursor
|
hyprcursor
|
||||||
hyprgraphics
|
hyprgraphics
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ echo 'static const std::map<std::string, std::string> SHADERS = {' >> ./src/rend
|
||||||
for filename in `ls ${SHADERS_SRC}`; do
|
for filename in `ls ${SHADERS_SRC}`; do
|
||||||
echo "-- ${filename}"
|
echo "-- ${filename}"
|
||||||
|
|
||||||
{ echo 'R"#('; cat ${SHADERS_SRC}/${filename}; echo ')#"'; } > ./src/render/shaders/${filename}.inc
|
{ echo -n 'R"#('; cat ${SHADERS_SRC}/${filename}; echo ')#"'; } > ./src/render/shaders/${filename}.inc
|
||||||
echo "{\"${filename}\"," >> ./src/render/shaders/Shaders.hpp
|
echo "{\"${filename}\"," >> ./src/render/shaders/Shaders.hpp
|
||||||
echo "#include \"./${filename}.inc\"" >> ./src/render/shaders/Shaders.hpp
|
echo "#include \"./${filename}.inc\"" >> ./src/render/shaders/Shaders.hpp
|
||||||
echo "}," >> ./src/render/shaders/Shaders.hpp
|
echo "}," >> ./src/render/shaders/Shaders.hpp
|
||||||
|
|
|
||||||
|
|
@ -1585,6 +1585,12 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
|
||||||
.type = CONFIG_OPTION_BOOL,
|
.type = CONFIG_OPTION_BOOL,
|
||||||
.data = SConfigOptionDescription::SBoolData{true},
|
.data = SConfigOptionDescription::SBoolData{true},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.value = "render:use_shader_blur_blend",
|
||||||
|
.description = "Use experimental blurred bg blending",
|
||||||
|
.type = CONFIG_OPTION_BOOL,
|
||||||
|
.data = SConfigOptionDescription::SBoolData{false},
|
||||||
|
},
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* cursor:
|
* cursor:
|
||||||
|
|
|
||||||
|
|
@ -800,6 +800,7 @@ CConfigManager::CConfigManager() {
|
||||||
registerConfigVar("render:cm_sdr_eotf", {"default"});
|
registerConfigVar("render:cm_sdr_eotf", {"default"});
|
||||||
registerConfigVar("render:commit_timing_enabled", Hyprlang::INT{1});
|
registerConfigVar("render:commit_timing_enabled", Hyprlang::INT{1});
|
||||||
registerConfigVar("render:icc_vcgt_enabled", Hyprlang::INT{1});
|
registerConfigVar("render:icc_vcgt_enabled", Hyprlang::INT{1});
|
||||||
|
registerConfigVar("render:use_shader_blur_blend", Hyprlang::INT{0});
|
||||||
|
|
||||||
registerConfigVar("ecosystem:no_update_news", Hyprlang::INT{0});
|
registerConfigVar("ecosystem:no_update_news", Hyprlang::INT{0});
|
||||||
registerConfigVar("ecosystem:no_donation_nag", Hyprlang::INT{0});
|
registerConfigVar("ecosystem:no_donation_nag", Hyprlang::INT{0});
|
||||||
|
|
|
||||||
|
|
@ -2049,7 +2049,12 @@ static std::string submapRequest(eHyprCtlOutputFormat format, std::string reques
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string reloadShaders(eHyprCtlOutputFormat format, std::string request) {
|
static std::string reloadShaders(eHyprCtlOutputFormat format, std::string request) {
|
||||||
if (g_pHyprOpenGL->initShaders())
|
CVarList vars(request, 0, ' ');
|
||||||
|
|
||||||
|
if (vars.size() > 2)
|
||||||
|
return "too many args";
|
||||||
|
|
||||||
|
if (g_pHyprOpenGL && g_pHyprRenderer->reloadShaders(vars.size() == 2 ? vars[1] : ""))
|
||||||
return format == FORMAT_JSON ? "{\"ok\": true}" : "ok";
|
return format == FORMAT_JSON ? "{\"ok\": true}" : "ok";
|
||||||
else
|
else
|
||||||
return format == FORMAT_JSON ? "{\"ok\": false}" : "error";
|
return format == FORMAT_JSON ? "{\"ok\": false}" : "error";
|
||||||
|
|
@ -2076,8 +2081,8 @@ CHyprCtl::CHyprCtl() {
|
||||||
registerCommand(SHyprCtlCommand{"locked", true, getIsLocked});
|
registerCommand(SHyprCtlCommand{"locked", true, getIsLocked});
|
||||||
registerCommand(SHyprCtlCommand{"descriptions", true, getDescriptions});
|
registerCommand(SHyprCtlCommand{"descriptions", true, getDescriptions});
|
||||||
registerCommand(SHyprCtlCommand{"submap", true, submapRequest});
|
registerCommand(SHyprCtlCommand{"submap", true, submapRequest});
|
||||||
registerCommand(SHyprCtlCommand{.name = "reloadshaders", .exact = true, .fn = reloadShaders});
|
|
||||||
|
|
||||||
|
registerCommand(SHyprCtlCommand{.name = "reloadshaders", .exact = false, .fn = reloadShaders});
|
||||||
registerCommand(SHyprCtlCommand{"monitors", false, monitorsRequest});
|
registerCommand(SHyprCtlCommand{"monitors", false, monitorsRequest});
|
||||||
registerCommand(SHyprCtlCommand{"reload", false, reloadRequest});
|
registerCommand(SHyprCtlCommand{"reload", false, reloadRequest});
|
||||||
registerCommand(SHyprCtlCommand{"plugin", false, dispatchPlugin});
|
registerCommand(SHyprCtlCommand{"plugin", false, dispatchPlugin});
|
||||||
|
|
|
||||||
|
|
@ -297,22 +297,6 @@ int NFormatUtils::minStride(const SPixelFormat* const fmt, int32_t width) {
|
||||||
return std::ceil((width * fmt->bytesPerBlock) / pixelsPerBlock(fmt));
|
return std::ceil((width * fmt->bytesPerBlock) / pixelsPerBlock(fmt));
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t NFormatUtils::drmFormatToGL(DRMFormat drm) {
|
|
||||||
switch (drm) {
|
|
||||||
case DRM_FORMAT_XRGB8888:
|
|
||||||
case DRM_FORMAT_XBGR8888: return GL_RGBA; // doesn't matter, opengl is gucci in this case.
|
|
||||||
case DRM_FORMAT_XRGB2101010:
|
|
||||||
case DRM_FORMAT_XBGR2101010: return GL_RGB10_A2;
|
|
||||||
default: return GL_RGBA;
|
|
||||||
}
|
|
||||||
UNREACHABLE();
|
|
||||||
return GL_RGBA;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t NFormatUtils::glFormatToType(uint32_t gl) {
|
|
||||||
return gl != GL_RGBA ? GL_UNSIGNED_INT_2_10_10_10_REV : GL_UNSIGNED_BYTE;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string NFormatUtils::drmFormatName(DRMFormat drm) {
|
std::string NFormatUtils::drmFormatName(DRMFormat drm) {
|
||||||
auto n = drmGetFormatName(drm);
|
auto n = drmGetFormatName(drm);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,8 +53,6 @@ namespace NFormatUtils {
|
||||||
bool isFormatOpaque(DRMFormat drm);
|
bool isFormatOpaque(DRMFormat drm);
|
||||||
int pixelsPerBlock(const SPixelFormat* const fmt);
|
int pixelsPerBlock(const SPixelFormat* const fmt);
|
||||||
int minStride(const SPixelFormat* const fmt, int32_t width);
|
int minStride(const SPixelFormat* const fmt, int32_t width);
|
||||||
uint32_t drmFormatToGL(DRMFormat drm);
|
|
||||||
uint32_t glFormatToType(uint32_t gl);
|
|
||||||
std::string drmFormatName(DRMFormat drm);
|
std::string drmFormatName(DRMFormat drm);
|
||||||
std::string drmModifierName(uint64_t mod);
|
std::string drmModifierName(uint64_t mod);
|
||||||
DRMFormat alphaFormat(DRMFormat prevFormat);
|
DRMFormat alphaFormat(DRMFormat prevFormat);
|
||||||
|
|
|
||||||
|
|
@ -1579,10 +1579,20 @@ Vector2D CMonitor::middle() {
|
||||||
return m_position + m_size / 2.f;
|
return m_position + m_size / 2.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Mat3x3& CMonitor::getTransformMatrix() {
|
||||||
|
return m_projMatrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Mat3x3& CMonitor::getScaleMatrix() {
|
||||||
|
return m_projOutputMatrix;
|
||||||
|
}
|
||||||
|
|
||||||
void CMonitor::updateMatrix() {
|
void CMonitor::updateMatrix() {
|
||||||
m_projMatrix = Mat3x3::identity();
|
m_projMatrix = Mat3x3::identity();
|
||||||
if (m_transform != WL_OUTPUT_TRANSFORM_NORMAL)
|
if (m_transform != WL_OUTPUT_TRANSFORM_NORMAL)
|
||||||
m_projMatrix.translate(m_pixelSize / 2.0).transform(Math::wlTransformToHyprutils(m_transform)).translate(-m_transformedSize / 2.0);
|
m_projMatrix.translate(m_pixelSize / 2.0).transform(Math::wlTransformToHyprutils(m_transform)).translate(-m_transformedSize / 2.0);
|
||||||
|
|
||||||
|
m_projOutputMatrix = Mat3x3::outputProjection(m_pixelSize, HYPRUTILS_TRANSFORM_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
WORKSPACEID CMonitor::activeWorkspaceID() {
|
WORKSPACEID CMonitor::activeWorkspaceID() {
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,7 @@ class CMonitor {
|
||||||
bool m_scheduledRecalc = false;
|
bool m_scheduledRecalc = false;
|
||||||
wl_output_transform m_transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
wl_output_transform m_transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||||
float m_xwaylandScale = 1.f;
|
float m_xwaylandScale = 1.f;
|
||||||
Mat3x3 m_projMatrix;
|
|
||||||
std::optional<Vector2D> m_forceSize;
|
std::optional<Vector2D> m_forceSize;
|
||||||
SP<Aquamarine::SOutputMode> m_currentMode;
|
SP<Aquamarine::SOutputMode> m_currentMode;
|
||||||
SP<Aquamarine::CSwapchain> m_cursorSwapchain;
|
SP<Aquamarine::CSwapchain> m_cursorSwapchain;
|
||||||
|
|
@ -303,7 +303,6 @@ class CMonitor {
|
||||||
void setSpecialWorkspace(const WORKSPACEID& id);
|
void setSpecialWorkspace(const WORKSPACEID& id);
|
||||||
void moveTo(const Vector2D& pos);
|
void moveTo(const Vector2D& pos);
|
||||||
Vector2D middle();
|
Vector2D middle();
|
||||||
void updateMatrix();
|
|
||||||
WORKSPACEID activeWorkspaceID();
|
WORKSPACEID activeWorkspaceID();
|
||||||
WORKSPACEID activeSpecialWorkspaceID();
|
WORKSPACEID activeSpecialWorkspaceID();
|
||||||
CBox logicalBox();
|
CBox logicalBox();
|
||||||
|
|
@ -335,6 +334,10 @@ class CMonitor {
|
||||||
bool inHDR();
|
bool inHDR();
|
||||||
bool gammaRampsInUse();
|
bool gammaRampsInUse();
|
||||||
|
|
||||||
|
//
|
||||||
|
const Mat3x3& getTransformMatrix();
|
||||||
|
const Mat3x3& getScaleMatrix();
|
||||||
|
|
||||||
/// Has an active workspace with a real fullscreen window (includes special workspace)
|
/// Has an active workspace with a real fullscreen window (includes special workspace)
|
||||||
bool inFullscreenMode();
|
bool inFullscreenMode();
|
||||||
/// Get fullscreen window from active or special workspace
|
/// Get fullscreen window from active or special workspace
|
||||||
|
|
@ -364,7 +367,12 @@ class CMonitor {
|
||||||
return m_position == rhs.m_position && m_size == rhs.m_size && m_name == rhs.m_name;
|
return m_position == rhs.m_position && m_size == rhs.m_size && m_name == rhs.m_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Mat3x3 m_projMatrix;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void updateMatrix();
|
||||||
|
Mat3x3 m_projOutputMatrix;
|
||||||
|
|
||||||
void setupDefaultWS(const SMonitorRule&);
|
void setupDefaultWS(const SMonitorRule&);
|
||||||
WORKSPACEID findAvailableDefaultWS();
|
WORKSPACEID findAvailableDefaultWS();
|
||||||
void commitDPMSState(bool state);
|
void commitDPMSState(bool state);
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,10 @@ std::string NTransferFunction::toString(eTF tf) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
eTF NTransferFunction::fromConfig() {
|
eTF NTransferFunction::fromConfig(bool useICC) {
|
||||||
|
if (useICC)
|
||||||
|
return TF_SRGB;
|
||||||
|
|
||||||
static auto PSDREOTF = CConfigValue<Hyprlang::STRING>("render:cm_sdr_eotf");
|
static auto PSDREOTF = CConfigValue<Hyprlang::STRING>("render:cm_sdr_eotf");
|
||||||
static auto sdrEOTF = NTransferFunction::fromString(*PSDREOTF);
|
static auto sdrEOTF = NTransferFunction::fromString(*PSDREOTF);
|
||||||
static auto P = Event::bus()->m_events.config.reloaded.listen([]() { sdrEOTF = NTransferFunction::fromString(*PSDREOTF); });
|
static auto P = Event::bus()->m_events.config.reloaded.listen([]() { sdrEOTF = NTransferFunction::fromString(*PSDREOTF); });
|
||||||
|
|
|
||||||
|
|
@ -15,5 +15,5 @@ namespace NTransferFunction {
|
||||||
eTF fromString(const std::string tfName);
|
eTF fromString(const std::string tfName);
|
||||||
std::string toString(eTF tf);
|
std::string toString(eTF tf);
|
||||||
|
|
||||||
eTF fromConfig();
|
eTF fromConfig(bool useICC = false);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -322,18 +322,22 @@ namespace NColorManagement {
|
||||||
|
|
||||||
using PImageDescription = WP<const CImageDescription>;
|
using PImageDescription = WP<const CImageDescription>;
|
||||||
|
|
||||||
static const auto DEFAULT_IMAGE_DESCRIPTION = CImageDescription::from(SImageDescription{.transferFunction = NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22,
|
static const auto DEFAULT_IMAGE_DESCRIPTION = CImageDescription::from(SImageDescription{
|
||||||
|
.transferFunction = NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22,
|
||||||
.primariesNameSet = true,
|
.primariesNameSet = true,
|
||||||
.primariesNamed = NColorManagement::CM_PRIMARIES_SRGB,
|
.primariesNamed = NColorManagement::CM_PRIMARIES_SRGB,
|
||||||
.primaries = NColorManagement::getPrimaries(NColorManagement::CM_PRIMARIES_SRGB),
|
.primaries = NColorManagement::getPrimaries(NColorManagement::CM_PRIMARIES_SRGB),
|
||||||
.luminances = {.min = SDR_MIN_LUMINANCE, .max = 80, .reference = 80}});
|
.luminances = {.min = SDR_MIN_LUMINANCE, .max = 80, .reference = 80},
|
||||||
|
});
|
||||||
|
|
||||||
static const auto DEFAULT_HDR_IMAGE_DESCRIPTION = CImageDescription::from(SImageDescription{.transferFunction = NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ,
|
static const auto DEFAULT_HDR_IMAGE_DESCRIPTION = CImageDescription::from(SImageDescription{
|
||||||
|
.transferFunction = NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ,
|
||||||
.primariesNameSet = true,
|
.primariesNameSet = true,
|
||||||
.primariesNamed = NColorManagement::CM_PRIMARIES_BT2020,
|
.primariesNamed = NColorManagement::CM_PRIMARIES_BT2020,
|
||||||
.primaries = NColorManagement::getPrimaries(NColorManagement::CM_PRIMARIES_BT2020),
|
.primaries = NColorManagement::getPrimaries(NColorManagement::CM_PRIMARIES_BT2020),
|
||||||
.luminances = {.min = HDR_MIN_LUMINANCE, .max = 10000, .reference = 203}});
|
.luminances = {.min = HDR_MIN_LUMINANCE, .max = 10000, .reference = 203},
|
||||||
;
|
});
|
||||||
|
|
||||||
static const auto SCRGB_IMAGE_DESCRIPTION = CImageDescription::from(SImageDescription{
|
static const auto SCRGB_IMAGE_DESCRIPTION = CImageDescription::from(SImageDescription{
|
||||||
.transferFunction = NColorManagement::CM_TRANSFER_FUNCTION_EXT_LINEAR,
|
.transferFunction = NColorManagement::CM_TRANSFER_FUNCTION_EXT_LINEAR,
|
||||||
.windowsScRGB = true,
|
.windowsScRGB = true,
|
||||||
|
|
@ -342,6 +346,6 @@ namespace NColorManagement {
|
||||||
.primaries = NColorPrimaries::BT709,
|
.primaries = NColorPrimaries::BT709,
|
||||||
.luminances = {.reference = 203},
|
.luminances = {.reference = 203},
|
||||||
});
|
});
|
||||||
;
|
|
||||||
|
|
||||||
|
static const auto LINEAR_IMAGE_DESCRIPTION = SCRGB_IMAGE_DESCRIPTION; // TODO any reason to use something different?
|
||||||
}
|
}
|
||||||
|
|
@ -164,6 +164,7 @@ void CScreenshareFrame::renderMonitor() {
|
||||||
|
|
||||||
auto TEXTURE = g_pHyprOpenGL->m_monitorRenderResources[PMONITOR].monitorMirrorFB.getTexture();
|
auto TEXTURE = g_pHyprOpenGL->m_monitorRenderResources[PMONITOR].monitorMirrorFB.getTexture();
|
||||||
|
|
||||||
|
const bool IS_CM_AWARE = PROTO::colorManagement && PROTO::colorManagement->isClientCMAware(m_session->m_client);
|
||||||
g_pHyprOpenGL->m_renderData.transformDamage = false;
|
g_pHyprOpenGL->m_renderData.transformDamage = false;
|
||||||
g_pHyprOpenGL->m_renderData.noSimplify = true;
|
g_pHyprOpenGL->m_renderData.noSimplify = true;
|
||||||
|
|
||||||
|
|
@ -173,7 +174,11 @@ void CScreenshareFrame::renderMonitor() {
|
||||||
.translate(-m_session->m_captureBox.pos()); // vvvv kinda ass-backwards but that's how I designed the renderer... sigh.
|
.translate(-m_session->m_captureBox.pos()); // vvvv kinda ass-backwards but that's how I designed the renderer... sigh.
|
||||||
g_pHyprOpenGL->pushMonitorTransformEnabled(true);
|
g_pHyprOpenGL->pushMonitorTransformEnabled(true);
|
||||||
g_pHyprOpenGL->setRenderModifEnabled(false);
|
g_pHyprOpenGL->setRenderModifEnabled(false);
|
||||||
g_pHyprOpenGL->renderTexturePrimitive(TEXTURE, monbox);
|
g_pHyprOpenGL->renderTexture(TEXTURE, monbox,
|
||||||
|
{
|
||||||
|
.cmBackToSRGB = !IS_CM_AWARE,
|
||||||
|
.cmBackToSRGBSource = !IS_CM_AWARE ? PMONITOR : nullptr,
|
||||||
|
});
|
||||||
g_pHyprOpenGL->setRenderModifEnabled(true);
|
g_pHyprOpenGL->setRenderModifEnabled(true);
|
||||||
g_pHyprOpenGL->popMonitorTransformEnabled();
|
g_pHyprOpenGL->popMonitorTransformEnabled();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
#include <GLES3/gl32.h>
|
#include <GLES3/gl32.h>
|
||||||
#include <hyprgraphics/color/Color.hpp>
|
#include <hyprgraphics/color/Color.hpp>
|
||||||
|
#include <hyprutils/math/Misc.hpp>
|
||||||
#include <hyprutils/string/String.hpp>
|
#include <hyprutils/string/String.hpp>
|
||||||
#include <hyprutils/path/Path.hpp>
|
#include <hyprutils/path/Path.hpp>
|
||||||
#include <numbers>
|
#include <numbers>
|
||||||
|
|
@ -31,6 +32,7 @@
|
||||||
#include "../managers/screenshare/ScreenshareManager.hpp"
|
#include "../managers/screenshare/ScreenshareManager.hpp"
|
||||||
#include "debug/HyprNotificationOverlay.hpp"
|
#include "debug/HyprNotificationOverlay.hpp"
|
||||||
#include "hyprerror/HyprError.hpp"
|
#include "hyprerror/HyprError.hpp"
|
||||||
|
#include "macros.hpp"
|
||||||
#include "pass/TexPassElement.hpp"
|
#include "pass/TexPassElement.hpp"
|
||||||
#include "pass/RectPassElement.hpp"
|
#include "pass/RectPassElement.hpp"
|
||||||
#include "pass/PreBlurElement.hpp"
|
#include "pass/PreBlurElement.hpp"
|
||||||
|
|
@ -44,20 +46,14 @@
|
||||||
#include <xf86drm.h>
|
#include <xf86drm.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <gbm.h>
|
#include <gbm.h>
|
||||||
#include <filesystem>
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include "./shaders/Shaders.hpp"
|
#include "ShaderLoader.hpp"
|
||||||
|
#include "Texture.hpp"
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
using namespace Hyprutils::OS;
|
using namespace Hyprutils::OS;
|
||||||
using namespace NColorManagement;
|
using namespace NColorManagement;
|
||||||
|
using namespace Render;
|
||||||
const std::vector<const char*> ASSET_PATHS = {
|
|
||||||
#ifdef DATAROOTDIR
|
|
||||||
DATAROOTDIR,
|
|
||||||
#endif
|
|
||||||
"/usr/share",
|
|
||||||
"/usr/local/share",
|
|
||||||
};
|
|
||||||
|
|
||||||
static inline void loadGLProc(void* pProc, const char* name) {
|
static inline void loadGLProc(void* pProc, const char* name) {
|
||||||
void* proc = rc<void*>(eglGetProcAddress(name));
|
void* proc = rc<void*>(eglGetProcAddress(name));
|
||||||
|
|
@ -880,124 +876,30 @@ void CHyprOpenGLImpl::setDamage(const CRegion& damage_, std::optional<CRegion> f
|
||||||
m_renderData.finalDamage.set(finalDamage.value_or(damage_));
|
m_renderData.finalDamage.set(finalDamage.value_or(damage_));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO notify user if bundled shader is newer than ~/.config override
|
static const std::vector<std::string> SHADER_INCLUDES = {
|
||||||
static std::string loadShader(const std::string& filename) {
|
"defines.h", "constants.h", "cm_helpers.glsl", "rounding.glsl", "CM.glsl", "tonemap.glsl", "gain.glsl",
|
||||||
const auto home = Hyprutils::Path::getHome();
|
"border.glsl", "shadow.glsl", "blurprepare.glsl", "blur1.glsl", "blur2.glsl", "blurFinish.glsl",
|
||||||
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<std::string, std::string>& includes) {
|
// order matters, see ePreparedFragmentShader
|
||||||
includes.insert({filename, loadShader(filename)});
|
const std::array<std::string, SH_FRAG_LAST> FRAG_SHADERS = {
|
||||||
}
|
"quad.frag", "passthru.frag", "rgbamatte.frag", "ext.frag", "blur1.frag", "blur2.frag",
|
||||||
|
"blurprepare.frag", "blurfinish.frag", "shadow.frag", "surface.frag", "border.frag", "glitch.frag",
|
||||||
|
};
|
||||||
|
|
||||||
static void processShaderIncludes(std::string& source, const std::map<std::string, std::string>& includes) {
|
bool CHyprOpenGLImpl::initShaders(const std::string& path) {
|
||||||
for (auto it = includes.begin(); it != includes.end(); ++it) {
|
|
||||||
Hyprutils::String::replaceInString(source, "#include \"" + it->first + "\"", it->second);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static const uint8_t MAX_INCLUDE_DEPTH = 3;
|
|
||||||
|
|
||||||
static std::string processShader(const std::string& filename, const std::map<std::string, std::string>& includes, const uint8_t includeDepth = 1) {
|
|
||||||
auto source = loadShader(filename);
|
|
||||||
for (auto i = 0; i < includeDepth; i++) {
|
|
||||||
processShaderIncludes(source, includes);
|
|
||||||
}
|
|
||||||
return source;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CHyprOpenGLImpl::initShaders() {
|
|
||||||
auto shaders = makeShared<SPreparedShaders>();
|
auto shaders = makeShared<SPreparedShaders>();
|
||||||
std::map<std::string, std::string> includes;
|
|
||||||
const bool isDynamic = m_shadersInitialized;
|
|
||||||
static const auto PCM = CConfigValue<Hyprlang::INT>("render:cm_enabled");
|
static const auto PCM = CConfigValue<Hyprlang::INT>("render:cm_enabled");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
loadShaderInclude("get_rgb_pixel.glsl", includes);
|
auto shaderLoader = makeUnique<CShaderLoader>(SHADER_INCLUDES, FRAG_SHADERS, path);
|
||||||
loadShaderInclude("get_rgba_pixel.glsl", includes);
|
|
||||||
loadShaderInclude("get_rgbx_pixel.glsl", includes);
|
|
||||||
loadShaderInclude("discard.glsl", includes);
|
|
||||||
loadShaderInclude("do_discard.glsl", includes);
|
|
||||||
loadShaderInclude("tint.glsl", includes);
|
|
||||||
loadShaderInclude("do_tint.glsl", includes);
|
|
||||||
loadShaderInclude("rounding.glsl", includes);
|
|
||||||
loadShaderInclude("do_rounding.glsl", includes);
|
|
||||||
loadShaderInclude("surface_CM.glsl", includes);
|
|
||||||
loadShaderInclude("CM.glsl", includes);
|
|
||||||
loadShaderInclude("do_CM.glsl", includes);
|
|
||||||
loadShaderInclude("tonemap.glsl", includes);
|
|
||||||
loadShaderInclude("do_tonemap.glsl", includes);
|
|
||||||
loadShaderInclude("sdr_mod.glsl", includes);
|
|
||||||
loadShaderInclude("do_sdr_mod.glsl", includes);
|
|
||||||
loadShaderInclude("primaries_xyz.glsl", includes);
|
|
||||||
loadShaderInclude("primaries_xyz_uniform.glsl", includes);
|
|
||||||
loadShaderInclude("primaries_xyz_const.glsl", includes);
|
|
||||||
loadShaderInclude("gain.glsl", includes);
|
|
||||||
loadShaderInclude("border.glsl", includes);
|
|
||||||
|
|
||||||
shaders->TEXVERTSRC = processShader("tex300.vert", includes);
|
shaders->TEXVERTSRC = shaderLoader->process("tex300.vert");
|
||||||
shaders->TEXVERTSRC320 = processShader("tex320.vert", includes);
|
shaders->TEXVERTSRC320 = shaderLoader->process("tex320.vert");
|
||||||
|
|
||||||
if (!*PCM)
|
m_cmSupported = *PCM;
|
||||||
m_cmSupported = false;
|
|
||||||
else {
|
|
||||||
std::vector<SFragShaderDesc> CM_SHADERS = {{
|
|
||||||
{SH_FRAG_CM_BLURPREPARE, "CMblurprepare.frag"},
|
|
||||||
{SH_FRAG_CM_BORDER1, "CMborder.frag"},
|
|
||||||
}};
|
|
||||||
|
|
||||||
bool success = false;
|
g_pShaderLoader = std::move(shaderLoader);
|
||||||
for (const auto& desc : CM_SHADERS) {
|
|
||||||
const auto fragSrc = processShader(desc.file, includes, MAX_INCLUDE_DEPTH);
|
|
||||||
|
|
||||||
if (!(success = shaders->frag[desc.id]->createProgram(shaders->TEXVERTSRC, fragSrc, true, true)))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_shadersInitialized && m_cmSupported && !success)
|
|
||||||
g_pHyprNotificationOverlay->addNotification(I18n::i18nEngine()->localize(I18n::TXT_KEY_NOTIF_CM_RELOAD_FAILED), CHyprColor{}, 15000, ICON_WARNING);
|
|
||||||
|
|
||||||
m_cmSupported = success;
|
|
||||||
|
|
||||||
if (!m_cmSupported)
|
|
||||||
Log::logger->log(
|
|
||||||
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!");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<SFragShaderDesc> FRAG_SHADERS = {{
|
|
||||||
{SH_FRAG_QUAD, "quad.frag"},
|
|
||||||
{SH_FRAG_PASSTHRURGBA, "passthru.frag"},
|
|
||||||
{SH_FRAG_MATTE, "rgbamatte.frag"},
|
|
||||||
{SH_FRAG_GLITCH, "glitch.frag"},
|
|
||||||
{SH_FRAG_EXT, "ext.frag"},
|
|
||||||
{SH_FRAG_BLUR1, "blur1.frag"},
|
|
||||||
{SH_FRAG_BLUR2, "blur2.frag"},
|
|
||||||
{SH_FRAG_BLURPREPARE, "blurprepare.frag"},
|
|
||||||
{SH_FRAG_BLURFINISH, "blurfinish.frag"},
|
|
||||||
{SH_FRAG_SHADOW, "shadow.frag"},
|
|
||||||
{SH_FRAG_BORDER1, "border.frag"},
|
|
||||||
}};
|
|
||||||
|
|
||||||
for (const auto& desc : FRAG_SHADERS) {
|
|
||||||
const auto fragSrc = processShader(desc.file, includes, MAX_INCLUDE_DEPTH);
|
|
||||||
|
|
||||||
if (!shaders->frag[desc.id]->createProgram(shaders->TEXVERTSRC, fragSrc, isDynamic))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
if (!m_shadersInitialized)
|
if (!m_shadersInitialized)
|
||||||
|
|
@ -1008,7 +910,6 @@ bool CHyprOpenGLImpl::initShaders() {
|
||||||
}
|
}
|
||||||
|
|
||||||
m_shaders = shaders;
|
m_shaders = shaders;
|
||||||
m_includes = includes;
|
|
||||||
m_shadersInitialized = true;
|
m_shadersInitialized = true;
|
||||||
|
|
||||||
Log::logger->log(Log::DEBUG, "Shaders initialized successfully.");
|
Log::logger->log(Log::DEBUG, "Shaders initialized successfully.");
|
||||||
|
|
@ -1192,7 +1093,7 @@ void CHyprOpenGLImpl::renderRectWithDamageInternal(const CBox& box, const CHyprC
|
||||||
newBox, Math::wlTransformToHyprutils(Math::invertTransform(!m_monitorTransformEnabled ? WL_OUTPUT_TRANSFORM_NORMAL : m_renderData.pMonitor->m_transform)), newBox.rot);
|
newBox, Math::wlTransformToHyprutils(Math::invertTransform(!m_monitorTransformEnabled ? WL_OUTPUT_TRANSFORM_NORMAL : m_renderData.pMonitor->m_transform)), newBox.rot);
|
||||||
Mat3x3 glMatrix = m_renderData.projection.copy().multiply(matrix);
|
Mat3x3 glMatrix = m_renderData.projection.copy().multiply(matrix);
|
||||||
|
|
||||||
auto shader = useShader(m_shaders->frag[SH_FRAG_QUAD]);
|
auto shader = useShader(getShaderVariant(SH_FRAG_QUAD, data.round > 0 ? SH_FEAT_ROUNDING : 0));
|
||||||
shader->setUniformMatrix3fv(SHADER_PROJ, 1, GL_TRUE, glMatrix.getMatrix());
|
shader->setUniformMatrix3fv(SHADER_PROJ, 1, GL_TRUE, glMatrix.getMatrix());
|
||||||
|
|
||||||
// premultiply the color as well as we don't work with straight alpha
|
// premultiply the color as well as we don't work with straight alpha
|
||||||
|
|
@ -1272,60 +1173,24 @@ static bool isHDR2SDR(const NColorManagement::SImageDescription& imageDescriptio
|
||||||
|
|
||||||
void CHyprOpenGLImpl::passCMUniforms(WP<CShader> shader, const NColorManagement::PImageDescription imageDescription,
|
void CHyprOpenGLImpl::passCMUniforms(WP<CShader> shader, const NColorManagement::PImageDescription imageDescription,
|
||||||
const NColorManagement::PImageDescription targetImageDescription, bool modifySDR, float sdrMinLuminance, int sdrMaxLuminance) {
|
const NColorManagement::PImageDescription targetImageDescription, bool modifySDR, float sdrMinLuminance, int sdrMaxLuminance) {
|
||||||
const auto sdrEOTF = NTransferFunction::fromConfig();
|
const auto settings = g_pHyprRenderer->getCMSettings(imageDescription, targetImageDescription, m_renderData.surface.valid() ? m_renderData.surface.lock() : nullptr, modifySDR,
|
||||||
|
sdrMinLuminance, sdrMaxLuminance);
|
||||||
|
|
||||||
if (m_renderData.surface.valid()) {
|
shader->setUniformInt(SHADER_SOURCE_TF, settings.sourceTF);
|
||||||
if (m_renderData.surface->m_colorManagement.valid()) {
|
shader->setUniformInt(SHADER_TARGET_TF, settings.targetTF);
|
||||||
if (sdrEOTF == NTransferFunction::TF_FORCED_GAMMA22 && imageDescription->value().transferFunction == NColorManagement::eTransferFunction::CM_TRANSFER_FUNCTION_SRGB)
|
shader->setUniformFloat2(SHADER_SRC_TF_RANGE, settings.srcTFRange.min, settings.srcTFRange.max);
|
||||||
shader->setUniformInt(SHADER_SOURCE_TF, NColorManagement::eTransferFunction::CM_TRANSFER_FUNCTION_GAMMA22);
|
shader->setUniformFloat2(SHADER_DST_TF_RANGE, settings.dstTFRange.min, settings.dstTFRange.max);
|
||||||
else
|
shader->setUniformFloat(SHADER_SRC_REF_LUMINANCE, settings.srcRefLuminance);
|
||||||
shader->setUniformInt(SHADER_SOURCE_TF, imageDescription->value().transferFunction);
|
shader->setUniformFloat(SHADER_DST_REF_LUMINANCE, settings.dstRefLuminance);
|
||||||
} else if (sdrEOTF == NTransferFunction::TF_SRGB)
|
shader->setUniformFloat(SHADER_MAX_LUMINANCE, settings.maxLuminance);
|
||||||
shader->setUniformInt(SHADER_SOURCE_TF, NColorManagement::eTransferFunction::CM_TRANSFER_FUNCTION_SRGB);
|
shader->setUniformFloat(SHADER_DST_MAX_LUMINANCE, settings.dstMaxLuminance);
|
||||||
else if (sdrEOTF == NTransferFunction::TF_GAMMA22 || sdrEOTF == NTransferFunction::TF_FORCED_GAMMA22)
|
shader->setUniformFloat(SHADER_SDR_SATURATION, settings.sdrSaturation);
|
||||||
shader->setUniformInt(SHADER_SOURCE_TF, NColorManagement::eTransferFunction::CM_TRANSFER_FUNCTION_GAMMA22);
|
shader->setUniformFloat(SHADER_SDR_BRIGHTNESS, settings.sdrBrightnessMultiplier);
|
||||||
else
|
|
||||||
shader->setUniformInt(SHADER_SOURCE_TF, imageDescription->value().transferFunction);
|
|
||||||
} else
|
|
||||||
shader->setUniformInt(SHADER_SOURCE_TF, imageDescription->value().transferFunction);
|
|
||||||
|
|
||||||
shader->setUniformInt(SHADER_TARGET_TF, targetImageDescription->value().transferFunction);
|
|
||||||
|
|
||||||
const auto targetPrimaries = targetImageDescription->getPrimaries();
|
|
||||||
const auto mat = targetPrimaries->value().toXYZ().mat();
|
|
||||||
const std::array<GLfloat, 9> glTargetPrimariesXYZ = {
|
|
||||||
mat[0][0], mat[1][0], mat[2][0], //
|
|
||||||
mat[0][1], mat[1][1], mat[2][1], //
|
|
||||||
mat[0][2], mat[1][2], mat[2][2], //
|
|
||||||
};
|
|
||||||
shader->setUniformMatrix3fv(SHADER_TARGET_PRIMARIES_XYZ, 1, false, glTargetPrimariesXYZ);
|
|
||||||
|
|
||||||
const bool needsSDRmod = modifySDR && isSDR2HDR(imageDescription->value(), targetImageDescription->value());
|
|
||||||
const bool needsHDRmod = !needsSDRmod && isHDR2SDR(imageDescription->value(), targetImageDescription->value());
|
|
||||||
|
|
||||||
shader->setUniformFloat2(SHADER_SRC_TF_RANGE, imageDescription->value().getTFMinLuminance(needsSDRmod ? sdrMinLuminance : -1),
|
|
||||||
imageDescription->value().getTFMaxLuminance(needsSDRmod ? sdrMaxLuminance : -1));
|
|
||||||
shader->setUniformFloat2(SHADER_DST_TF_RANGE, targetImageDescription->value().getTFMinLuminance(needsSDRmod ? sdrMinLuminance : -1),
|
|
||||||
targetImageDescription->value().getTFMaxLuminance(needsSDRmod ? sdrMaxLuminance : -1));
|
|
||||||
|
|
||||||
shader->setUniformFloat(SHADER_SRC_REF_LUMINANCE, imageDescription->value().luminances.reference);
|
|
||||||
shader->setUniformFloat(SHADER_DST_REF_LUMINANCE, targetImageDescription->value().luminances.reference);
|
|
||||||
|
|
||||||
const float maxLuminance = needsHDRmod ?
|
|
||||||
imageDescription->value().getTFMaxLuminance(-1) :
|
|
||||||
(imageDescription->value().luminances.max > 0 ? imageDescription->value().luminances.max : imageDescription->value().luminances.reference);
|
|
||||||
|
|
||||||
shader->setUniformFloat(SHADER_MAX_LUMINANCE, maxLuminance * targetImageDescription->value().luminances.reference / imageDescription->value().luminances.reference);
|
|
||||||
shader->setUniformFloat(SHADER_DST_MAX_LUMINANCE, targetImageDescription->value().luminances.max > 0 ? targetImageDescription->value().luminances.max : 10000);
|
|
||||||
shader->setUniformFloat(SHADER_SDR_SATURATION, needsSDRmod && m_renderData.pMonitor->m_sdrSaturation > 0 ? m_renderData.pMonitor->m_sdrSaturation : 1.0f);
|
|
||||||
shader->setUniformFloat(SHADER_SDR_BRIGHTNESS, needsSDRmod && m_renderData.pMonitor->m_sdrBrightness > 0 ? m_renderData.pMonitor->m_sdrBrightness : 1.0f);
|
|
||||||
|
|
||||||
if (!targetImageDescription->value().icc.present) {
|
if (!targetImageDescription->value().icc.present) {
|
||||||
const auto cacheKey = std::make_pair(imageDescription->id(), targetImageDescription->id());
|
const auto cacheKey = std::make_pair(imageDescription->id(), targetImageDescription->id());
|
||||||
|
|
||||||
if (!primariesConversionCache.contains(cacheKey)) {
|
if (!primariesConversionCache.contains(cacheKey)) {
|
||||||
auto conversion = imageDescription->getPrimaries()->convertMatrix(targetImageDescription->getPrimaries());
|
const auto& mat = settings.convertMatrix;
|
||||||
const auto mat = conversion.mat();
|
|
||||||
const std::array<GLfloat, 9> glConvertMatrix = {
|
const std::array<GLfloat, 9> glConvertMatrix = {
|
||||||
mat[0][0], mat[1][0], mat[2][0], //
|
mat[0][0], mat[1][0], mat[2][0], //
|
||||||
mat[0][1], mat[1][1], mat[2][1], //
|
mat[0][1], mat[1][1], mat[2][1], //
|
||||||
|
|
@ -1335,12 +1200,14 @@ void CHyprOpenGLImpl::passCMUniforms(WP<CShader> shader, const NColorManagement:
|
||||||
}
|
}
|
||||||
shader->setUniformMatrix3fv(SHADER_CONVERT_MATRIX, 1, false, primariesConversionCache[cacheKey]);
|
shader->setUniformMatrix3fv(SHADER_CONVERT_MATRIX, 1, false, primariesConversionCache[cacheKey]);
|
||||||
|
|
||||||
shader->setUniformInt(SHADER_USE_ICC, 0);
|
const auto mat = settings.dstPrimaries2XYZ;
|
||||||
shader->setUniformInt(SHADER_LUT_3D, 8); // req'd for ogl
|
const std::array<GLfloat, 9> glTargetPrimariesXYZ = {
|
||||||
|
mat[0][0], mat[1][0], mat[2][0], //
|
||||||
|
mat[0][1], mat[1][1], mat[2][1], //
|
||||||
|
mat[0][2], mat[1][2], mat[2][2], //
|
||||||
|
};
|
||||||
|
shader->setUniformMatrix3fv(SHADER_TARGET_PRIMARIES_XYZ, 1, false, glTargetPrimariesXYZ);
|
||||||
} else {
|
} else {
|
||||||
// ICC path, use a 3D LUT
|
|
||||||
shader->setUniformInt(SHADER_USE_ICC, 1);
|
|
||||||
|
|
||||||
// TODO: this sucks
|
// TODO: this sucks
|
||||||
GLCALL(glActiveTexture(GL_TEXTURE8));
|
GLCALL(glActiveTexture(GL_TEXTURE8));
|
||||||
targetImageDescription->value().icc.lutTexture->bind();
|
targetImageDescription->value().icc.lutTexture->bind();
|
||||||
|
|
@ -1353,193 +1220,24 @@ void CHyprOpenGLImpl::passCMUniforms(WP<CShader> shader, const NColorManagement:
|
||||||
}
|
}
|
||||||
|
|
||||||
void CHyprOpenGLImpl::passCMUniforms(WP<CShader> shader, const PImageDescription imageDescription) {
|
void CHyprOpenGLImpl::passCMUniforms(WP<CShader> shader, const PImageDescription imageDescription) {
|
||||||
passCMUniforms(shader, imageDescription, m_renderData.pMonitor->m_imageDescription, true, m_renderData.pMonitor->m_sdrMinLuminance, m_renderData.pMonitor->m_sdrMaxLuminance);
|
passCMUniforms(shader, imageDescription, g_pHyprRenderer->workBufferImageDescription(), true, m_renderData.pMonitor->m_sdrMinLuminance,
|
||||||
|
m_renderData.pMonitor->m_sdrMaxLuminance);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CHyprOpenGLImpl::renderTextureInternal(SP<CTexture> tex, const CBox& box, const STextureRenderData& data) {
|
WP<CShader> CHyprOpenGLImpl::renderToOutputInternal() {
|
||||||
RASSERT(m_renderData.pMonitor, "Tried to render texture without begin()!");
|
|
||||||
RASSERT((tex->m_texID > 0), "Attempted to draw nullptr texture!");
|
|
||||||
|
|
||||||
TRACY_GPU_ZONE("RenderTextureInternalWithDamage");
|
|
||||||
|
|
||||||
float alpha = std::clamp(data.a, 0.f, 1.f);
|
|
||||||
|
|
||||||
if (data.damage->empty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
CBox newBox = box;
|
|
||||||
m_renderData.renderModif.applyToBox(newBox);
|
|
||||||
|
|
||||||
static const auto PDT = CConfigValue<Hyprlang::INT>("debug:damage_tracking");
|
static const auto PDT = CConfigValue<Hyprlang::INT>("debug:damage_tracking");
|
||||||
static const auto PPASS = CConfigValue<Hyprlang::INT>("render:cm_fs_passthrough");
|
|
||||||
static const auto PENABLECM = CConfigValue<Hyprlang::INT>("render:cm_enabled");
|
|
||||||
static const auto PCURSORTIMEOUT = CConfigValue<Hyprlang::FLOAT>("cursor:inactive_timeout");
|
static const auto PCURSORTIMEOUT = CConfigValue<Hyprlang::FLOAT>("cursor:inactive_timeout");
|
||||||
|
|
||||||
// get the needed transform for this texture
|
WP<CShader> shader =
|
||||||
const auto MONITOR_INVERTED = Math::wlTransformToHyprutils(Math::invertTransform(m_renderData.pMonitor->m_transform));
|
g_pHyprRenderer->m_crashingInProgress ? getShaderVariant(SH_FRAG_GLITCH) : (m_finalScreenShader->program() ? m_finalScreenShader : getShaderVariant(SH_FRAG_PASSTHRURGBA));
|
||||||
Hyprutils::Math::eTransform TRANSFORM = tex->m_transform;
|
|
||||||
|
|
||||||
if (m_monitorTransformEnabled)
|
|
||||||
TRANSFORM = Math::composeTransform(MONITOR_INVERTED, TRANSFORM);
|
|
||||||
|
|
||||||
Mat3x3 matrix = m_renderData.monitorProjection.projectBox(newBox, TRANSFORM, newBox.rot);
|
|
||||||
Mat3x3 glMatrix = m_renderData.projection.copy().multiply(matrix);
|
|
||||||
|
|
||||||
WP<CShader> shader;
|
|
||||||
|
|
||||||
const bool CRASHING = m_applyFinalShader && g_pHyprRenderer->m_crashingInProgress;
|
|
||||||
const bool CUSTOM_FINAL_SHADER = !CRASHING && m_applyFinalShader && m_finalScreenShader->program();
|
|
||||||
|
|
||||||
uint8_t shaderFeatures = 0;
|
|
||||||
|
|
||||||
if (CRASHING)
|
|
||||||
shader = m_shaders->frag[SH_FRAG_GLITCH];
|
|
||||||
else if (CUSTOM_FINAL_SHADER)
|
|
||||||
shader = m_finalScreenShader;
|
|
||||||
else {
|
|
||||||
if (m_applyFinalShader)
|
|
||||||
shaderFeatures &= ~SH_FEAT_RGBA;
|
|
||||||
else {
|
|
||||||
switch (tex->m_type) {
|
|
||||||
case TEXTURE_RGBA: shaderFeatures |= SH_FEAT_RGBA; break;
|
|
||||||
case TEXTURE_RGBX: shaderFeatures &= ~SH_FEAT_RGBA; break;
|
|
||||||
|
|
||||||
case TEXTURE_EXTERNAL: shader = m_shaders->frag[SH_FRAG_EXT]; break; // might be unused
|
|
||||||
default: RASSERT(false, "tex->m_iTarget unsupported!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.finalMonitorCM || (m_renderData.currentWindow && m_renderData.currentWindow->m_ruleApplicator->RGBX().valueOrDefault()))
|
|
||||||
shaderFeatures &= ~SH_FEAT_RGBA;
|
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
tex->bind();
|
|
||||||
|
|
||||||
tex->setTexParameter(GL_TEXTURE_WRAP_S, data.wrapX);
|
|
||||||
tex->setTexParameter(GL_TEXTURE_WRAP_T, data.wrapY);
|
|
||||||
|
|
||||||
if (m_renderData.useNearestNeighbor) {
|
|
||||||
tex->setTexParameter(GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
||||||
tex->setTexParameter(GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
||||||
} else {
|
|
||||||
tex->setTexParameter(GL_TEXTURE_MAG_FILTER, tex->magFilter);
|
|
||||||
tex->setTexParameter(GL_TEXTURE_MIN_FILTER, tex->minFilter);
|
|
||||||
}
|
|
||||||
|
|
||||||
const bool isHDRSurface = m_renderData.surface.valid() && m_renderData.surface->m_colorManagement.valid() ? m_renderData.surface->m_colorManagement->isHDR() : false;
|
|
||||||
const bool canPassHDRSurface = isHDRSurface && !m_renderData.surface->m_colorManagement->isWindowsScRGB(); // windows scRGB requires CM shader
|
|
||||||
|
|
||||||
// Color pipeline:
|
|
||||||
// Client ---> sRGB chosen EOTF (render buf) ---> Monitor (target)
|
|
||||||
//
|
|
||||||
|
|
||||||
const auto CONFIG_SDR_EOTF = NTransferFunction::fromConfig();
|
|
||||||
const bool IS_MONITOR_ICC = m_renderData.pMonitor->m_imageDescription.valid() && m_renderData.pMonitor->m_imageDescription->value().icc.present;
|
|
||||||
const auto CHOSEN_SDR_EOTF = [&] {
|
|
||||||
// if the monitor is ICC'd, use SRGB for best ΔE.
|
|
||||||
if (IS_MONITOR_ICC)
|
|
||||||
return CM_TRANSFER_FUNCTION_SRGB;
|
|
||||||
|
|
||||||
// otherwise use configured
|
|
||||||
if (CONFIG_SDR_EOTF != NTransferFunction::TF_SRGB)
|
|
||||||
return CM_TRANSFER_FUNCTION_GAMMA22;
|
|
||||||
return CM_TRANSFER_FUNCTION_SRGB;
|
|
||||||
}();
|
|
||||||
const auto WORK_BUFFER_IMAGE_DESCRIPTION = CImageDescription::from(NColorManagement::SImageDescription{.transferFunction = CHOSEN_SDR_EOTF});
|
|
||||||
|
|
||||||
// chosenSdrEotf contains the valid eotf for this display
|
|
||||||
|
|
||||||
const auto SOURCE_IMAGE_DESCRIPTION = [&] {
|
|
||||||
// if valid CM surface, use that as a source
|
|
||||||
if (m_renderData.surface.valid() && m_renderData.surface->m_colorManagement.valid())
|
|
||||||
return CImageDescription::from(m_renderData.surface->m_colorManagement->imageDescription());
|
|
||||||
|
|
||||||
// otherwise, if we are CM'ing back into source, use chosen, because that's what our work buffer is in
|
|
||||||
// the same applies to the final monitor CM
|
|
||||||
if (data.cmBackToSRGB || data.finalMonitorCM) // NOLINTNEXTLINE
|
|
||||||
return WORK_BUFFER_IMAGE_DESCRIPTION;
|
|
||||||
|
|
||||||
// otherwise, default
|
|
||||||
return DEFAULT_IMAGE_DESCRIPTION;
|
|
||||||
}();
|
|
||||||
|
|
||||||
const auto TARGET_IMAGE_DESCRIPTION = [&] {
|
|
||||||
// if we are CM'ing back, use default sRGB
|
|
||||||
if (data.cmBackToSRGB)
|
|
||||||
return DEFAULT_IMAGE_DESCRIPTION;
|
|
||||||
|
|
||||||
// for final CM, use the target description
|
|
||||||
if (data.finalMonitorCM)
|
|
||||||
return m_renderData.pMonitor->m_imageDescription;
|
|
||||||
|
|
||||||
// otherwise, use chosen, we're drawing into the work buffer
|
|
||||||
// NOLINTNEXTLINE
|
|
||||||
return WORK_BUFFER_IMAGE_DESCRIPTION;
|
|
||||||
}();
|
|
||||||
|
|
||||||
const bool CANT_CHECK_CM_EQUALITY = data.cmBackToSRGB || data.finalMonitorCM || (!m_renderData.surface || !m_renderData.surface->m_colorManagement);
|
|
||||||
|
|
||||||
const bool skipCM = data.noCM /* manual CM disable */
|
|
||||||
|| !*PENABLECM || !m_cmSupported /* CM unsupported or disabled */
|
|
||||||
|| m_renderData.pMonitor->doesNoShaderCM() /* no shader needed */
|
|
||||||
|| (SOURCE_IMAGE_DESCRIPTION->id() == TARGET_IMAGE_DESCRIPTION->id() && !CANT_CHECK_CM_EQUALITY) /* Source and target have the same image description */
|
|
||||||
|| (((*PPASS && canPassHDRSurface) ||
|
|
||||||
(*PPASS == 1 && !isHDRSurface && m_renderData.pMonitor->m_cmType != NCMType::CM_HDR && m_renderData.pMonitor->m_cmType != NCMType::CM_HDR_EDID)) &&
|
|
||||||
m_renderData.pMonitor->inFullscreenMode()) /* Fullscreen window with pass cm enabled */;
|
|
||||||
|
|
||||||
if (data.discardActive)
|
|
||||||
shaderFeatures |= SH_FEAT_DISCARD;
|
|
||||||
|
|
||||||
if (data.allowDim && m_renderData.currentWindow && (m_renderData.currentWindow->m_notRespondingTint->value() > 0 || m_renderData.currentWindow->m_dimPercent->value() > 0))
|
|
||||||
shaderFeatures |= SH_FEAT_TINT;
|
|
||||||
|
|
||||||
if (data.round > 0)
|
|
||||||
shaderFeatures |= SH_FEAT_ROUNDING;
|
|
||||||
|
|
||||||
if (!skipCM) {
|
|
||||||
shaderFeatures |= SH_FEAT_CM;
|
|
||||||
|
|
||||||
const bool needsSDRmod = isSDR2HDR(SOURCE_IMAGE_DESCRIPTION->value(), TARGET_IMAGE_DESCRIPTION->value());
|
|
||||||
const bool needsHDRmod = !needsSDRmod && isHDR2SDR(SOURCE_IMAGE_DESCRIPTION->value(), TARGET_IMAGE_DESCRIPTION->value());
|
|
||||||
const float maxLuminance = needsHDRmod ?
|
|
||||||
SOURCE_IMAGE_DESCRIPTION->value().getTFMaxLuminance(-1) :
|
|
||||||
(SOURCE_IMAGE_DESCRIPTION->value().luminances.max > 0 ? SOURCE_IMAGE_DESCRIPTION->value().luminances.max : SOURCE_IMAGE_DESCRIPTION->value().luminances.reference);
|
|
||||||
const auto dstMaxLuminance = TARGET_IMAGE_DESCRIPTION->value().luminances.max > 0 ? TARGET_IMAGE_DESCRIPTION->value().luminances.max : 10000;
|
|
||||||
|
|
||||||
if (maxLuminance >= dstMaxLuminance * 1.01)
|
|
||||||
shaderFeatures |= SH_FEAT_TONEMAP;
|
|
||||||
|
|
||||||
if (data.finalMonitorCM &&
|
|
||||||
(SOURCE_IMAGE_DESCRIPTION->value().transferFunction == CM_TRANSFER_FUNCTION_SRGB ||
|
|
||||||
SOURCE_IMAGE_DESCRIPTION->value().transferFunction == CM_TRANSFER_FUNCTION_GAMMA22) &&
|
|
||||||
TARGET_IMAGE_DESCRIPTION->value().transferFunction == CM_TRANSFER_FUNCTION_ST2084_PQ &&
|
|
||||||
((m_renderData.pMonitor->m_sdrSaturation > 0 && m_renderData.pMonitor->m_sdrSaturation != 1.0f) ||
|
|
||||||
(m_renderData.pMonitor->m_sdrBrightness > 0 && m_renderData.pMonitor->m_sdrBrightness != 1.0f)))
|
|
||||||
shaderFeatures |= SH_FEAT_SDR_MOD;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!shader)
|
|
||||||
shader = getSurfaceShader(shaderFeatures);
|
|
||||||
|
|
||||||
shader = useShader(shader);
|
shader = useShader(shader);
|
||||||
|
|
||||||
if (!skipCM) {
|
if (*PDT == 0 || g_pHyprRenderer->m_crashingInProgress)
|
||||||
if (data.finalMonitorCM)
|
|
||||||
passCMUniforms(shader, SOURCE_IMAGE_DESCRIPTION, TARGET_IMAGE_DESCRIPTION, true, m_renderData.pMonitor->m_sdrMinLuminance, m_renderData.pMonitor->m_sdrMaxLuminance);
|
|
||||||
else
|
|
||||||
passCMUniforms(shader, SOURCE_IMAGE_DESCRIPTION, TARGET_IMAGE_DESCRIPTION, true, -1, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
shader->setUniformMatrix3fv(SHADER_PROJ, 1, GL_TRUE, glMatrix.getMatrix());
|
|
||||||
shader->setUniformInt(SHADER_TEX, 0);
|
|
||||||
|
|
||||||
if ((CUSTOM_FINAL_SHADER && *PDT == 0) || CRASHING)
|
|
||||||
shader->setUniformFloat(SHADER_TIME, m_globalTimer.getSeconds() - shader->getInitialTime());
|
shader->setUniformFloat(SHADER_TIME, m_globalTimer.getSeconds() - shader->getInitialTime());
|
||||||
else if (CUSTOM_FINAL_SHADER)
|
else
|
||||||
shader->setUniformFloat(SHADER_TIME, 0.F);
|
shader->setUniformFloat(SHADER_TIME, 0.f);
|
||||||
|
|
||||||
if (CUSTOM_FINAL_SHADER) {
|
|
||||||
shader->setUniformInt(SHADER_WL_OUTPUT, m_renderData.pMonitor->m_id);
|
shader->setUniformInt(SHADER_WL_OUTPUT, m_renderData.pMonitor->m_id);
|
||||||
shader->setUniformFloat2(SHADER_FULL_SIZE, m_renderData.pMonitor->m_pixelSize.x, m_renderData.pMonitor->m_pixelSize.y);
|
shader->setUniformFloat2(SHADER_FULL_SIZE, m_renderData.pMonitor->m_pixelSize.x, m_renderData.pMonitor->m_pixelSize.y);
|
||||||
shader->setUniformFloat(SHADER_POINTER_INACTIVE_TIMEOUT, *PCURSORTIMEOUT);
|
shader->setUniformFloat(SHADER_POINTER_INACTIVE_TIMEOUT, *PCURSORTIMEOUT);
|
||||||
|
|
@ -1548,9 +1246,8 @@ void CHyprOpenGLImpl::renderTextureInternal(SP<CTexture> tex, const CBox& box, c
|
||||||
shader->setUniformInt(SHADER_POINTER_SHAPE, g_pHyprRenderer->m_lastCursorData.shape);
|
shader->setUniformInt(SHADER_POINTER_SHAPE, g_pHyprRenderer->m_lastCursorData.shape);
|
||||||
shader->setUniformInt(SHADER_POINTER_SHAPE_PREVIOUS, g_pHyprRenderer->m_lastCursorData.shapePrevious);
|
shader->setUniformInt(SHADER_POINTER_SHAPE_PREVIOUS, g_pHyprRenderer->m_lastCursorData.shapePrevious);
|
||||||
shader->setUniformFloat(SHADER_POINTER_SIZE, g_pCursorManager->getScaledSize());
|
shader->setUniformFloat(SHADER_POINTER_SIZE, g_pCursorManager->getScaledSize());
|
||||||
}
|
|
||||||
|
|
||||||
if (CUSTOM_FINAL_SHADER && *PDT == 0) {
|
if (*PDT == 0) {
|
||||||
PHLMONITORREF pMonitor = m_renderData.pMonitor;
|
PHLMONITORREF pMonitor = m_renderData.pMonitor;
|
||||||
Vector2D p = ((g_pInputManager->getMouseCoordsInternal() - pMonitor->m_position) * pMonitor->m_scale);
|
Vector2D p = ((g_pInputManager->getMouseCoordsInternal() - pMonitor->m_position) * pMonitor->m_scale);
|
||||||
p = p.transform(Math::wlTransformToHyprutils(pMonitor->m_transform), pMonitor->m_pixelSize);
|
p = p.transform(Math::wlTransformToHyprutils(pMonitor->m_transform), pMonitor->m_pixelSize);
|
||||||
|
|
@ -1576,7 +1273,7 @@ void CHyprOpenGLImpl::renderTextureInternal(SP<CTexture> tex, const CBox& box, c
|
||||||
shader->setUniformFloat(SHADER_POINTER_LAST_ACTIVE, g_pInputManager->m_lastCursorMovement.getSeconds());
|
shader->setUniformFloat(SHADER_POINTER_LAST_ACTIVE, g_pInputManager->m_lastCursorMovement.getSeconds());
|
||||||
shader->setUniformFloat(SHADER_POINTER_SWITCH_TIME, g_pHyprRenderer->m_lastCursorData.switchedTimer.getSeconds());
|
shader->setUniformFloat(SHADER_POINTER_SWITCH_TIME, g_pHyprRenderer->m_lastCursorData.switchedTimer.getSeconds());
|
||||||
|
|
||||||
} else if (CUSTOM_FINAL_SHADER) {
|
} else {
|
||||||
shader->setUniformFloat2(SHADER_POINTER, 0.f, 0.f);
|
shader->setUniformFloat2(SHADER_POINTER, 0.f, 0.f);
|
||||||
|
|
||||||
static const std::vector<float> pressedPosDefault(POINTER_PRESSED_HISTORY_LENGTH * 2uz, 0.f);
|
static const std::vector<float> pressedPosDefault(POINTER_PRESSED_HISTORY_LENGTH * 2uz, 0.f);
|
||||||
|
|
@ -1590,13 +1287,141 @@ void CHyprOpenGLImpl::renderTextureInternal(SP<CTexture> tex, const CBox& box, c
|
||||||
shader->setUniformFloat(SHADER_POINTER_SWITCH_TIME, 0.f);
|
shader->setUniformFloat(SHADER_POINTER_SWITCH_TIME, 0.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CRASHING) {
|
if (g_pHyprRenderer->m_crashingInProgress) {
|
||||||
shader->setUniformFloat(SHADER_DISTORT, g_pHyprRenderer->m_crashingDistort);
|
shader->setUniformFloat(SHADER_DISTORT, g_pHyprRenderer->m_crashingDistort);
|
||||||
shader->setUniformFloat2(SHADER_FULL_SIZE, m_renderData.pMonitor->m_pixelSize.x, m_renderData.pMonitor->m_pixelSize.y);
|
shader->setUniformFloat2(SHADER_FULL_SIZE, m_renderData.pMonitor->m_pixelSize.x, m_renderData.pMonitor->m_pixelSize.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
WP<CShader> CHyprOpenGLImpl::renderToFBInternal(const STextureRenderData& data, eTextureType texType, const CBox& newBox) {
|
||||||
|
static const auto PPASS = CConfigValue<Hyprlang::INT>("render:cm_fs_passthrough");
|
||||||
|
static const auto PENABLECM = CConfigValue<Hyprlang::INT>("render:cm_enabled");
|
||||||
|
static auto PBLEND = CConfigValue<Hyprlang::INT>("render:use_shader_blur_blend");
|
||||||
|
|
||||||
|
float alpha = std::clamp(data.a, 0.f, 1.f);
|
||||||
|
|
||||||
|
WP<CShader> shader;
|
||||||
|
ShaderFeatureFlags shaderFeatures = 0;
|
||||||
|
|
||||||
|
switch (texType) {
|
||||||
|
case TEXTURE_RGBA: shaderFeatures |= SH_FEAT_RGBA; break;
|
||||||
|
case TEXTURE_RGBX: shaderFeatures &= ~SH_FEAT_RGBA; break;
|
||||||
|
|
||||||
|
// TODO set correct features
|
||||||
|
case TEXTURE_EXTERNAL: shader = getShaderVariant(SH_FRAG_EXT, SH_FEAT_ROUNDING | SH_FEAT_DISCARD | SH_FEAT_TINT); break; // might be unused
|
||||||
|
default: RASSERT(false, "tex->m_iTarget unsupported!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.finalMonitorCM || (m_renderData.currentWindow && m_renderData.currentWindow->m_ruleApplicator->RGBX().valueOrDefault()))
|
||||||
|
shaderFeatures &= ~SH_FEAT_RGBA;
|
||||||
|
|
||||||
|
const auto surface = m_renderData.surface;
|
||||||
|
const bool isHDRSurface = surface.valid() && surface->m_colorManagement.valid() ? surface->m_colorManagement->isHDR() : false;
|
||||||
|
const bool canPassHDRSurface = isHDRSurface && !surface->m_colorManagement->isWindowsScRGB(); // windows scRGB requires CM shader
|
||||||
|
|
||||||
|
const auto WORK_BUFFER_IMAGE_DESCRIPTION = g_pHyprRenderer->workBufferImageDescription();
|
||||||
|
|
||||||
|
// chosenSdrEotf contains the valid eotf for this display
|
||||||
|
|
||||||
|
const auto SOURCE_IMAGE_DESCRIPTION = [&] {
|
||||||
|
// if valid CM surface, use that as a source
|
||||||
|
if (m_renderData.surface.valid() && m_renderData.surface->m_colorManagement.valid())
|
||||||
|
return CImageDescription::from(m_renderData.surface->m_colorManagement->imageDescription());
|
||||||
|
|
||||||
|
// otherwise, if we are CM'ing back into source, use chosen, because that's what our work buffer is in
|
||||||
|
// the same applies to the final monitor CM
|
||||||
|
if (data.cmBackToSRGB || data.finalMonitorCM) // NOLINTNEXTLINE
|
||||||
|
return WORK_BUFFER_IMAGE_DESCRIPTION;
|
||||||
|
|
||||||
|
// otherwise, default
|
||||||
|
return DEFAULT_IMAGE_DESCRIPTION;
|
||||||
|
}();
|
||||||
|
|
||||||
|
const auto TARGET_IMAGE_DESCRIPTION = [&] {
|
||||||
|
// if we are CM'ing back, use default sRGB
|
||||||
|
if (data.cmBackToSRGB)
|
||||||
|
return DEFAULT_IMAGE_DESCRIPTION;
|
||||||
|
|
||||||
|
// for final CM, use the target description
|
||||||
|
if (data.finalMonitorCM)
|
||||||
|
return m_renderData.pMonitor->m_imageDescription;
|
||||||
|
// otherwise, use chosen, we're drawing into the work buffer
|
||||||
|
// NOLINTNEXTLINE
|
||||||
|
return WORK_BUFFER_IMAGE_DESCRIPTION;
|
||||||
|
}();
|
||||||
|
|
||||||
|
if (data.blur && *PBLEND && data.blurredBG)
|
||||||
|
shaderFeatures |= SH_FEAT_BLUR;
|
||||||
|
|
||||||
|
if (data.discardActive)
|
||||||
|
shaderFeatures |= SH_FEAT_DISCARD;
|
||||||
|
|
||||||
|
const bool CANT_CHECK_CM_EQUALITY = data.cmBackToSRGB || data.finalMonitorCM || (!m_renderData.surface || !m_renderData.surface->m_colorManagement);
|
||||||
|
|
||||||
|
const bool skipCM = !*PENABLECM || !m_cmSupported /* CM unsupported or disabled */
|
||||||
|
|| m_renderData.pMonitor->doesNoShaderCM() /* no shader needed */
|
||||||
|
|| (SOURCE_IMAGE_DESCRIPTION->id() == TARGET_IMAGE_DESCRIPTION->id() && !CANT_CHECK_CM_EQUALITY) /* Source and target have the same image description */
|
||||||
|
|| (((*PPASS && canPassHDRSurface) ||
|
||||||
|
(*PPASS == 1 && !isHDRSurface && m_renderData.pMonitor->m_cmType != NCMType::CM_HDR && m_renderData.pMonitor->m_cmType != NCMType::CM_HDR_EDID)) &&
|
||||||
|
m_renderData.pMonitor->inFullscreenMode()) /* Fullscreen window with pass cm enabled */;
|
||||||
|
|
||||||
|
if (data.allowDim && m_renderData.currentWindow && (m_renderData.currentWindow->m_notRespondingTint->value() > 0 || m_renderData.currentWindow->m_dimPercent->value() > 0))
|
||||||
|
shaderFeatures |= SH_FEAT_TINT;
|
||||||
|
|
||||||
|
if (data.round > 0)
|
||||||
|
shaderFeatures |= SH_FEAT_ROUNDING;
|
||||||
|
|
||||||
|
if (!skipCM) {
|
||||||
|
shaderFeatures |= SH_FEAT_CM;
|
||||||
|
|
||||||
|
if (TARGET_IMAGE_DESCRIPTION->value().icc.present)
|
||||||
|
shaderFeatures |= SH_FEAT_ICC;
|
||||||
|
else {
|
||||||
|
const bool needsSDRmod = isSDR2HDR(SOURCE_IMAGE_DESCRIPTION->value(), TARGET_IMAGE_DESCRIPTION->value());
|
||||||
|
const bool needsHDRmod = !needsSDRmod && isHDR2SDR(SOURCE_IMAGE_DESCRIPTION->value(), TARGET_IMAGE_DESCRIPTION->value());
|
||||||
|
const float maxLuminance = needsHDRmod ?
|
||||||
|
SOURCE_IMAGE_DESCRIPTION->value().getTFMaxLuminance(-1) :
|
||||||
|
(SOURCE_IMAGE_DESCRIPTION->value().luminances.max > 0 ? SOURCE_IMAGE_DESCRIPTION->value().luminances.max : SOURCE_IMAGE_DESCRIPTION->value().luminances.reference);
|
||||||
|
const auto dstMaxLuminance = TARGET_IMAGE_DESCRIPTION->value().luminances.max > 0 ? TARGET_IMAGE_DESCRIPTION->value().luminances.max : 10000;
|
||||||
|
|
||||||
|
if (maxLuminance >= dstMaxLuminance * 1.01)
|
||||||
|
shaderFeatures |= SH_FEAT_TONEMAP;
|
||||||
|
|
||||||
|
if (data.finalMonitorCM &&
|
||||||
|
(SOURCE_IMAGE_DESCRIPTION->value().transferFunction == CM_TRANSFER_FUNCTION_SRGB ||
|
||||||
|
SOURCE_IMAGE_DESCRIPTION->value().transferFunction == CM_TRANSFER_FUNCTION_GAMMA22) &&
|
||||||
|
TARGET_IMAGE_DESCRIPTION->value().transferFunction == CM_TRANSFER_FUNCTION_ST2084_PQ &&
|
||||||
|
((m_renderData.pMonitor->m_sdrSaturation > 0 && m_renderData.pMonitor->m_sdrSaturation != 1.0f) ||
|
||||||
|
(m_renderData.pMonitor->m_sdrBrightness > 0 && m_renderData.pMonitor->m_sdrBrightness != 1.0f)))
|
||||||
|
shaderFeatures |= SH_FEAT_SDR_MOD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!shader)
|
||||||
|
shader = getShaderVariant(SH_FRAG_SURFACE, shaderFeatures);
|
||||||
|
shader = useShader(shader);
|
||||||
|
|
||||||
|
if (!skipCM) {
|
||||||
|
if (data.finalMonitorCM || data.cmBackToSRGB)
|
||||||
|
passCMUniforms(shader, SOURCE_IMAGE_DESCRIPTION, TARGET_IMAGE_DESCRIPTION, true, m_renderData.pMonitor->m_sdrMinLuminance, m_renderData.pMonitor->m_sdrMaxLuminance);
|
||||||
|
else
|
||||||
|
passCMUniforms(shader, SOURCE_IMAGE_DESCRIPTION);
|
||||||
|
}
|
||||||
|
|
||||||
shader->setUniformFloat(SHADER_ALPHA, alpha);
|
shader->setUniformFloat(SHADER_ALPHA, alpha);
|
||||||
|
|
||||||
|
if (shaderFeatures & SH_FEAT_BLUR) {
|
||||||
|
shader->setUniformInt(SHADER_BLURRED_BG, 1);
|
||||||
|
// shader->setUniformFloat2(SHADER_UV_OFFSET, 0, 0);
|
||||||
|
shader->setUniformFloat2(SHADER_UV_OFFSET, newBox.x / m_renderData.pMonitor->m_transformedSize.x, newBox.y / m_renderData.pMonitor->m_transformedSize.y);
|
||||||
|
shader->setUniformFloat2(SHADER_UV_SIZE, newBox.width / m_renderData.pMonitor->m_transformedSize.x, newBox.height / m_renderData.pMonitor->m_transformedSize.y);
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE0 + 1);
|
||||||
|
data.blurredBG->bind();
|
||||||
|
}
|
||||||
|
|
||||||
if (data.discardActive) {
|
if (data.discardActive) {
|
||||||
shader->setUniformInt(SHADER_DISCARD_OPAQUE, !!(m_renderData.discardMode & DISCARD_OPAQUE));
|
shader->setUniformInt(SHADER_DISCARD_OPAQUE, !!(m_renderData.discardMode & DISCARD_OPAQUE));
|
||||||
shader->setUniformInt(SHADER_DISCARD_ALPHA, !!(m_renderData.discardMode & DISCARD_ALPHA));
|
shader->setUniformInt(SHADER_DISCARD_ALPHA, !!(m_renderData.discardMode & DISCARD_ALPHA));
|
||||||
|
|
@ -1612,7 +1437,6 @@ void CHyprOpenGLImpl::renderTextureInternal(SP<CTexture> tex, const CBox& box, c
|
||||||
|
|
||||||
const auto TOPLEFT = Vector2D(transformedBox.x, transformedBox.y);
|
const auto TOPLEFT = Vector2D(transformedBox.x, transformedBox.y);
|
||||||
const auto FULLSIZE = Vector2D(transformedBox.width, transformedBox.height);
|
const auto FULLSIZE = Vector2D(transformedBox.width, transformedBox.height);
|
||||||
|
|
||||||
// Rounded corners
|
// Rounded corners
|
||||||
shader->setUniformFloat2(SHADER_TOP_LEFT, TOPLEFT.x, TOPLEFT.y);
|
shader->setUniformFloat2(SHADER_TOP_LEFT, TOPLEFT.x, TOPLEFT.y);
|
||||||
shader->setUniformFloat2(SHADER_FULL_SIZE, FULLSIZE.x, FULLSIZE.y);
|
shader->setUniformFloat2(SHADER_FULL_SIZE, FULLSIZE.x, FULLSIZE.y);
|
||||||
|
|
@ -1633,8 +1457,53 @@ void CHyprOpenGLImpl::renderTextureInternal(SP<CTexture> tex, const CBox& box, c
|
||||||
} else
|
} else
|
||||||
shader->setUniformInt(SHADER_APPLY_TINT, 0);
|
shader->setUniformInt(SHADER_APPLY_TINT, 0);
|
||||||
|
|
||||||
glBindVertexArray(shader->getUniformLocation(SHADER_SHADER_VAO));
|
return shader;
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, shader->getUniformLocation(SHADER_SHADER_VBO));
|
}
|
||||||
|
|
||||||
|
void CHyprOpenGLImpl::renderTextureInternal(SP<CTexture> tex, const CBox& box, const STextureRenderData& data) {
|
||||||
|
RASSERT(m_renderData.pMonitor, "Tried to render texture without begin()!");
|
||||||
|
RASSERT((tex->m_texID > 0), "Attempted to draw nullptr texture!");
|
||||||
|
|
||||||
|
TRACY_GPU_ZONE("RenderTextureInternalWithDamage");
|
||||||
|
|
||||||
|
if (data.damage->empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
CBox newBox = box;
|
||||||
|
m_renderData.renderModif.applyToBox(newBox);
|
||||||
|
|
||||||
|
// get the needed transform for this texture
|
||||||
|
const auto MONITOR_INVERTED = Math::wlTransformToHyprutils(Math::invertTransform(m_renderData.pMonitor->m_transform));
|
||||||
|
Hyprutils::Math::eTransform TRANSFORM = tex->m_transform;
|
||||||
|
|
||||||
|
if (m_monitorTransformEnabled)
|
||||||
|
TRANSFORM = Math::composeTransform(MONITOR_INVERTED, TRANSFORM);
|
||||||
|
|
||||||
|
Mat3x3 matrix = m_renderData.monitorProjection.projectBox(newBox, TRANSFORM, newBox.rot);
|
||||||
|
Mat3x3 glMatrix = m_renderData.projection.copy().multiply(matrix);
|
||||||
|
|
||||||
|
const bool renderToOutput = m_applyFinalShader && g_pHyprRenderer->workBufferImageDescription()->id() == m_renderData.pMonitor->m_imageDescription->id();
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
tex->bind();
|
||||||
|
|
||||||
|
tex->setTexParameter(GL_TEXTURE_WRAP_S, data.wrapX);
|
||||||
|
tex->setTexParameter(GL_TEXTURE_WRAP_T, data.wrapY);
|
||||||
|
|
||||||
|
if (m_renderData.useNearestNeighbor) {
|
||||||
|
tex->setTexParameter(GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
tex->setTexParameter(GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
} else {
|
||||||
|
tex->setTexParameter(GL_TEXTURE_MAG_FILTER, tex->magFilter);
|
||||||
|
tex->setTexParameter(GL_TEXTURE_MIN_FILTER, tex->minFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto shader = renderToOutput ? renderToOutputInternal() : renderToFBInternal(data, tex->m_type, newBox);
|
||||||
|
|
||||||
|
shader->setUniformMatrix3fv(SHADER_PROJ, 1, GL_TRUE, glMatrix.getMatrix());
|
||||||
|
shader->setUniformInt(SHADER_TEX, 0);
|
||||||
|
GLCALL(glBindVertexArray(shader->getUniformLocation(SHADER_SHADER_VAO)));
|
||||||
|
GLCALL(glBindBuffer(GL_ARRAY_BUFFER, shader->getUniformLocation(SHADER_SHADER_VBO)));
|
||||||
|
|
||||||
// this tells GPU can keep reading the old block for previous draws while the CPU writes to a new one.
|
// this tells GPU can keep reading the old block for previous draws while the CPU writes to a new one.
|
||||||
// to avoid stalls if renderTextureInternal is called multiple times on same renderpass
|
// to avoid stalls if renderTextureInternal is called multiple times on same renderpass
|
||||||
|
|
@ -1719,7 +1588,7 @@ void CHyprOpenGLImpl::renderTexturePrimitive(SP<CTexture> tex, const CBox& box)
|
||||||
tex->setTexParameter(GL_TEXTURE_MIN_FILTER, tex->minFilter);
|
tex->setTexParameter(GL_TEXTURE_MIN_FILTER, tex->minFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto shader = useShader(m_shaders->frag[SH_FRAG_PASSTHRURGBA]);
|
auto shader = useShader(getShaderVariant(SH_FRAG_PASSTHRURGBA));
|
||||||
shader->setUniformMatrix3fv(SHADER_PROJ, 1, GL_TRUE, glMatrix.getMatrix());
|
shader->setUniformMatrix3fv(SHADER_PROJ, 1, GL_TRUE, glMatrix.getMatrix());
|
||||||
shader->setUniformInt(SHADER_TEX, 0);
|
shader->setUniformInt(SHADER_TEX, 0);
|
||||||
glBindVertexArray(shader->getUniformLocation(SHADER_SHADER_VAO));
|
glBindVertexArray(shader->getUniformLocation(SHADER_SHADER_VAO));
|
||||||
|
|
@ -1751,7 +1620,7 @@ void CHyprOpenGLImpl::renderTextureMatte(SP<CTexture> tex, const CBox& box, CFra
|
||||||
Mat3x3 matrix = m_renderData.monitorProjection.projectBox(newBox, TRANSFORM, newBox.rot);
|
Mat3x3 matrix = m_renderData.monitorProjection.projectBox(newBox, TRANSFORM, newBox.rot);
|
||||||
Mat3x3 glMatrix = m_renderData.projection.copy().multiply(matrix);
|
Mat3x3 glMatrix = m_renderData.projection.copy().multiply(matrix);
|
||||||
|
|
||||||
auto shader = useShader(m_shaders->frag[SH_FRAG_MATTE]);
|
auto shader = useShader(getShaderVariant(SH_FRAG_MATTE));
|
||||||
shader->setUniformMatrix3fv(SHADER_PROJ, 1, GL_TRUE, glMatrix.getMatrix());
|
shader->setUniformMatrix3fv(SHADER_PROJ, 1, GL_TRUE, glMatrix.getMatrix());
|
||||||
shader->setUniformInt(SHADER_TEX, 0);
|
shader->setUniformInt(SHADER_TEX, 0);
|
||||||
shader->setUniformInt(SHADER_ALPHA_MATTE, 1);
|
shader->setUniformInt(SHADER_ALPHA_MATTE, 1);
|
||||||
|
|
@ -1826,6 +1695,7 @@ CFramebuffer* CHyprOpenGLImpl::blurFramebufferWithDamage(float a, CRegion* origi
|
||||||
{
|
{
|
||||||
static auto PBLURCONTRAST = CConfigValue<Hyprlang::FLOAT>("decoration:blur:contrast");
|
static auto PBLURCONTRAST = CConfigValue<Hyprlang::FLOAT>("decoration:blur:contrast");
|
||||||
static auto PBLURBRIGHTNESS = CConfigValue<Hyprlang::FLOAT>("decoration:blur:brightness");
|
static auto PBLURBRIGHTNESS = CConfigValue<Hyprlang::FLOAT>("decoration:blur:brightness");
|
||||||
|
static auto PBLEND = CConfigValue<Hyprlang::INT>("render:use_shader_blur_blend");
|
||||||
|
|
||||||
PMIRRORSWAPFB->bind();
|
PMIRRORSWAPFB->bind();
|
||||||
|
|
||||||
|
|
@ -1838,7 +1708,26 @@ CFramebuffer* CHyprOpenGLImpl::blurFramebufferWithDamage(float a, CRegion* origi
|
||||||
|
|
||||||
WP<CShader> shader;
|
WP<CShader> shader;
|
||||||
|
|
||||||
shader = useShader(m_shaders->frag[SH_FRAG_BLURPREPARE]);
|
// From FB to sRGB
|
||||||
|
const bool skipCM = !m_cmSupported || g_pHyprRenderer->workBufferImageDescription()->id() == DEFAULT_IMAGE_DESCRIPTION->id();
|
||||||
|
if (!skipCM) {
|
||||||
|
shader = useShader(getShaderVariant(SH_FRAG_BLURPREPARE, SH_FEAT_CM));
|
||||||
|
passCMUniforms(shader, m_renderData.pMonitor->m_imageDescription, DEFAULT_IMAGE_DESCRIPTION);
|
||||||
|
shader->setUniformFloat(SHADER_SDR_SATURATION,
|
||||||
|
m_renderData.pMonitor->m_sdrSaturation > 0 &&
|
||||||
|
m_renderData.pMonitor->m_imageDescription->value().transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ ?
|
||||||
|
m_renderData.pMonitor->m_sdrSaturation :
|
||||||
|
1.0f);
|
||||||
|
shader->setUniformFloat(SHADER_SDR_BRIGHTNESS,
|
||||||
|
m_renderData.pMonitor->m_sdrBrightness > 0 &&
|
||||||
|
m_renderData.pMonitor->m_imageDescription->value().transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ ?
|
||||||
|
m_renderData.pMonitor->m_sdrBrightness :
|
||||||
|
1.0f);
|
||||||
|
} else
|
||||||
|
shader = useShader(getShaderVariant(SH_FRAG_BLURPREPARE));
|
||||||
|
|
||||||
|
Mat3x3 matrix = m_renderData.monitorProjection.projectBox(MONITORBOX, *PBLEND ? HYPRUTILS_TRANSFORM_NORMAL : TRANSFORM);
|
||||||
|
Mat3x3 glMatrix = m_renderData.projection.copy().multiply(matrix);
|
||||||
shader->setUniformMatrix3fv(SHADER_PROJ, 1, GL_TRUE, glMatrix.getMatrix());
|
shader->setUniformMatrix3fv(SHADER_PROJ, 1, GL_TRUE, glMatrix.getMatrix());
|
||||||
shader->setUniformFloat(SHADER_CONTRAST, *PBLURCONTRAST);
|
shader->setUniformFloat(SHADER_CONTRAST, *PBLURCONTRAST);
|
||||||
shader->setUniformFloat(SHADER_BRIGHTNESS, *PBLURBRIGHTNESS);
|
shader->setUniformFloat(SHADER_BRIGHTNESS, *PBLURBRIGHTNESS);
|
||||||
|
|
@ -1910,13 +1799,13 @@ CFramebuffer* CHyprOpenGLImpl::blurFramebufferWithDamage(float a, CRegion* origi
|
||||||
CRegion tempDamage{damage};
|
CRegion tempDamage{damage};
|
||||||
|
|
||||||
// and draw
|
// and draw
|
||||||
auto shader = useShader(m_shaders->frag[SH_FRAG_BLUR1]);
|
auto shader = useShader(getShaderVariant(SH_FRAG_BLUR1));
|
||||||
for (auto i = 1; i <= BLUR_PASSES; ++i) {
|
for (auto i = 1; i <= BLUR_PASSES; ++i) {
|
||||||
tempDamage = damage.copy().scale(1.f / (1 << i));
|
tempDamage = damage.copy().scale(1.f / (1 << i));
|
||||||
drawPass(shader, SH_FRAG_BLUR1, &tempDamage); // down
|
drawPass(shader, SH_FRAG_BLUR1, &tempDamage); // down
|
||||||
}
|
}
|
||||||
|
|
||||||
shader = useShader(m_shaders->frag[SH_FRAG_BLUR2]);
|
shader = useShader(getShaderVariant(SH_FRAG_BLUR2));
|
||||||
for (auto i = BLUR_PASSES - 1; i >= 0; --i) {
|
for (auto i = BLUR_PASSES - 1; i >= 0; --i) {
|
||||||
tempDamage = damage.copy().scale(1.f / (1 << i)); // when upsampling we make the region twice as big
|
tempDamage = damage.copy().scale(1.f / (1 << i)); // when upsampling we make the region twice as big
|
||||||
drawPass(shader, SH_FRAG_BLUR2, &tempDamage); // up
|
drawPass(shader, SH_FRAG_BLUR2, &tempDamage); // up
|
||||||
|
|
@ -1940,7 +1829,7 @@ CFramebuffer* CHyprOpenGLImpl::blurFramebufferWithDamage(float a, CRegion* origi
|
||||||
|
|
||||||
currentTex->setTexParameter(GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
currentTex->setTexParameter(GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
|
||||||
auto shader = useShader(m_shaders->frag[SH_FRAG_BLURFINISH]);
|
auto shader = useShader(getShaderVariant(SH_FRAG_BLURFINISH));
|
||||||
shader->setUniformMatrix3fv(SHADER_PROJ, 1, GL_TRUE, glMatrix.getMatrix());
|
shader->setUniformMatrix3fv(SHADER_PROJ, 1, GL_TRUE, glMatrix.getMatrix());
|
||||||
shader->setUniformFloat(SHADER_NOISE, *PBLURNOISE);
|
shader->setUniformFloat(SHADER_NOISE, *PBLURNOISE);
|
||||||
shader->setUniformFloat(SHADER_BRIGHTNESS, *PBLURBRIGHTNESS);
|
shader->setUniformFloat(SHADER_BRIGHTNESS, *PBLURBRIGHTNESS);
|
||||||
|
|
@ -2132,6 +2021,8 @@ void CHyprOpenGLImpl::renderTextureWithBlurInternal(SP<CTexture> tex, const CBox
|
||||||
|
|
||||||
TRACY_GPU_ZONE("RenderTextureWithBlur");
|
TRACY_GPU_ZONE("RenderTextureWithBlur");
|
||||||
|
|
||||||
|
static auto PBLEND = CConfigValue<Hyprlang::INT>("render:use_shader_blur_blend");
|
||||||
|
|
||||||
// make a damage region for this window
|
// make a damage region for this window
|
||||||
CRegion texDamage{m_renderData.damage};
|
CRegion texDamage{m_renderData.damage};
|
||||||
texDamage.intersect(box.x, box.y, box.width, box.height);
|
texDamage.intersect(box.x, box.y, box.width, box.height);
|
||||||
|
|
@ -2178,7 +2069,10 @@ void CHyprOpenGLImpl::renderTextureWithBlurInternal(SP<CTexture> tex, const CBox
|
||||||
|
|
||||||
m_renderData.currentFB->bind();
|
m_renderData.currentFB->bind();
|
||||||
|
|
||||||
const auto NEEDS_STENCIL = m_renderData.discardMode != 0;
|
auto blurredBG = POUTFB->getTexture();
|
||||||
|
|
||||||
|
const auto NEEDS_STENCIL = m_renderData.discardMode != 0 && (!data.blockBlurOptimization || (m_renderData.discardMode & DISCARD_ALPHA));
|
||||||
|
if (!*PBLEND) {
|
||||||
|
|
||||||
if (NEEDS_STENCIL) {
|
if (NEEDS_STENCIL) {
|
||||||
scissor(nullptr); // allow the entire window and stencil to render
|
scissor(nullptr); // allow the entire window and stencil to render
|
||||||
|
|
@ -2191,9 +2085,6 @@ void CHyprOpenGLImpl::renderTextureWithBlurInternal(SP<CTexture> tex, const CBox
|
||||||
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
|
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
|
||||||
|
|
||||||
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
|
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
|
||||||
if (USENEWOPTIMIZE && !(m_renderData.discardMode & DISCARD_ALPHA))
|
|
||||||
renderRect(box, CHyprColor(0, 0, 0, 0), SRectRenderData{.round = data.round, .roundingPower = data.roundingPower});
|
|
||||||
else
|
|
||||||
renderTexture(tex, box,
|
renderTexture(tex, box,
|
||||||
STextureRenderData{.a = data.a,
|
STextureRenderData{.a = data.a,
|
||||||
.round = data.round,
|
.round = data.round,
|
||||||
|
|
@ -2201,7 +2092,8 @@ void CHyprOpenGLImpl::renderTextureWithBlurInternal(SP<CTexture> tex, const CBox
|
||||||
.discardActive = true,
|
.discardActive = true,
|
||||||
.allowCustomUV = true,
|
.allowCustomUV = true,
|
||||||
.wrapX = data.wrapX,
|
.wrapX = data.wrapX,
|
||||||
.wrapY = data.wrapY}); // discard opaque
|
.wrapY = data.wrapY}); // discard opaque and alpha < discardOpacity
|
||||||
|
|
||||||
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||||
|
|
||||||
glStencilFunc(GL_EQUAL, 1, 0xFF);
|
glStencilFunc(GL_EQUAL, 1, 0xFF);
|
||||||
|
|
@ -2226,9 +2118,10 @@ void CHyprOpenGLImpl::renderTextureWithBlurInternal(SP<CTexture> tex, const CBox
|
||||||
|
|
||||||
static auto PBLURIGNOREOPACITY = CConfigValue<Hyprlang::INT>("decoration:blur:ignore_opacity");
|
static auto PBLURIGNOREOPACITY = CConfigValue<Hyprlang::INT>("decoration:blur:ignore_opacity");
|
||||||
pushMonitorTransformEnabled(true);
|
pushMonitorTransformEnabled(true);
|
||||||
|
bool renderModif = m_renderData.renderModif.enabled;
|
||||||
if (!USENEWOPTIMIZE)
|
if (!USENEWOPTIMIZE)
|
||||||
setRenderModifEnabled(false);
|
setRenderModifEnabled(false);
|
||||||
renderTextureInternal(POUTFB->getTexture(), box,
|
renderTextureInternal(blurredBG, box,
|
||||||
STextureRenderData{
|
STextureRenderData{
|
||||||
.damage = &texDamage,
|
.damage = &texDamage,
|
||||||
.a = (*PBLURIGNOREOPACITY ? data.blurA : data.a * data.blurA) * data.overallA,
|
.a = (*PBLURIGNOREOPACITY ? data.blurA : data.a * data.blurA) * data.overallA,
|
||||||
|
|
@ -2241,26 +2134,31 @@ void CHyprOpenGLImpl::renderTextureWithBlurInternal(SP<CTexture> tex, const CBox
|
||||||
.wrapY = data.wrapY,
|
.wrapY = data.wrapY,
|
||||||
});
|
});
|
||||||
if (!USENEWOPTIMIZE)
|
if (!USENEWOPTIMIZE)
|
||||||
setRenderModifEnabled(true);
|
setRenderModifEnabled(renderModif);
|
||||||
popMonitorTransformEnabled();
|
popMonitorTransformEnabled();
|
||||||
|
|
||||||
|
if (NEEDS_STENCIL)
|
||||||
|
setCapStatus(GL_STENCIL_TEST, false);
|
||||||
|
|
||||||
m_renderData.primarySurfaceUVTopLeft = LASTTL;
|
m_renderData.primarySurfaceUVTopLeft = LASTTL;
|
||||||
m_renderData.primarySurfaceUVBottomRight = LASTBR;
|
m_renderData.primarySurfaceUVBottomRight = LASTBR;
|
||||||
|
}
|
||||||
|
|
||||||
// draw window
|
// draw window
|
||||||
setCapStatus(GL_STENCIL_TEST, false);
|
|
||||||
renderTextureInternal(tex, box,
|
renderTextureInternal(tex, box,
|
||||||
STextureRenderData{
|
STextureRenderData{
|
||||||
.damage = &texDamage,
|
.damage = &texDamage,
|
||||||
.a = data.a * data.overallA,
|
.a = data.a * data.overallA,
|
||||||
|
.blur = *PBLEND,
|
||||||
.round = data.round,
|
.round = data.round,
|
||||||
.roundingPower = data.roundingPower,
|
.roundingPower = data.roundingPower,
|
||||||
.discardActive = false,
|
.discardActive = *PBLEND && NEEDS_STENCIL,
|
||||||
.allowCustomUV = true,
|
.allowCustomUV = true,
|
||||||
.allowDim = true,
|
.allowDim = true,
|
||||||
.noAA = false,
|
.noAA = false,
|
||||||
.wrapX = data.wrapX,
|
.wrapX = data.wrapX,
|
||||||
.wrapY = data.wrapY,
|
.wrapY = data.wrapY,
|
||||||
|
.blurredBG = blurredBG,
|
||||||
});
|
});
|
||||||
|
|
||||||
m_renderData.currentFB->invalidate({GL_STENCIL_ATTACHMENT});
|
m_renderData.currentFB->invalidate({GL_STENCIL_ATTACHMENT});
|
||||||
|
|
@ -2300,7 +2198,15 @@ void CHyprOpenGLImpl::renderBorder(const CBox& box, const CGradientValueData& gr
|
||||||
const auto BLEND = m_blend;
|
const auto BLEND = m_blend;
|
||||||
blend(true);
|
blend(true);
|
||||||
|
|
||||||
WP<CShader> shader = useShader(m_shaders->frag[SH_FRAG_BORDER1]);
|
WP<CShader> shader;
|
||||||
|
|
||||||
|
const bool IS_ICC = g_pHyprRenderer->workBufferImageDescription()->value().icc.present;
|
||||||
|
const bool skipCM = !m_cmSupported || g_pHyprRenderer->workBufferImageDescription()->id() == DEFAULT_IMAGE_DESCRIPTION->id();
|
||||||
|
if (!skipCM) {
|
||||||
|
shader = useShader(getShaderVariant(SH_FRAG_BORDER1, SH_FEAT_ROUNDING | SH_FEAT_CM | (IS_ICC ? SH_FEAT_ICC : SH_FEAT_TONEMAP | SH_FEAT_SDR_MOD)));
|
||||||
|
passCMUniforms(shader, DEFAULT_IMAGE_DESCRIPTION);
|
||||||
|
} else
|
||||||
|
shader = useShader(getShaderVariant(SH_FRAG_BORDER1, SH_FEAT_ROUNDING));
|
||||||
|
|
||||||
shader->setUniformMatrix3fv(SHADER_PROJ, 1, GL_TRUE, glMatrix.getMatrix());
|
shader->setUniformMatrix3fv(SHADER_PROJ, 1, GL_TRUE, glMatrix.getMatrix());
|
||||||
shader->setUniform4fv(SHADER_GRADIENT, grad.m_colorsOkLabA.size() / 4, grad.m_colorsOkLabA);
|
shader->setUniform4fv(SHADER_GRADIENT, grad.m_colorsOkLabA.size() / 4, grad.m_colorsOkLabA);
|
||||||
|
|
@ -2379,7 +2285,14 @@ void CHyprOpenGLImpl::renderBorder(const CBox& box, const CGradientValueData& gr
|
||||||
const auto BLEND = m_blend;
|
const auto BLEND = m_blend;
|
||||||
blend(true);
|
blend(true);
|
||||||
|
|
||||||
WP<CShader> shader = useShader(m_shaders->frag[SH_FRAG_BORDER1]);
|
WP<CShader> shader;
|
||||||
|
const bool IS_ICC = g_pHyprRenderer->workBufferImageDescription()->value().icc.present;
|
||||||
|
const bool skipCM = !m_cmSupported || g_pHyprRenderer->workBufferImageDescription()->id() == DEFAULT_IMAGE_DESCRIPTION->id();
|
||||||
|
if (!skipCM) {
|
||||||
|
shader = useShader(getShaderVariant(SH_FRAG_BORDER1, SH_FEAT_ROUNDING | SH_FEAT_CM | (IS_ICC ? SH_FEAT_ICC : SH_FEAT_TONEMAP | SH_FEAT_SDR_MOD)));
|
||||||
|
passCMUniforms(shader, DEFAULT_IMAGE_DESCRIPTION);
|
||||||
|
} else
|
||||||
|
shader = useShader(getShaderVariant(SH_FRAG_BORDER1, SH_FEAT_ROUNDING));
|
||||||
|
|
||||||
shader->setUniformMatrix3fv(SHADER_PROJ, 1, GL_TRUE, glMatrix.getMatrix());
|
shader->setUniformMatrix3fv(SHADER_PROJ, 1, GL_TRUE, glMatrix.getMatrix());
|
||||||
shader->setUniform4fv(SHADER_GRADIENT, grad1.m_colorsOkLabA.size() / 4, grad1.m_colorsOkLabA);
|
shader->setUniform4fv(SHADER_GRADIENT, grad1.m_colorsOkLabA.size() / 4, grad1.m_colorsOkLabA);
|
||||||
|
|
@ -2452,7 +2365,11 @@ void CHyprOpenGLImpl::renderRoundedShadow(const CBox& box, int round, float roun
|
||||||
|
|
||||||
blend(true);
|
blend(true);
|
||||||
|
|
||||||
auto shader = useShader(m_shaders->frag[SH_FRAG_SHADOW]);
|
const bool IS_ICC = g_pHyprRenderer->workBufferImageDescription()->value().icc.present;
|
||||||
|
const bool skipCM = !m_cmSupported || g_pHyprRenderer->workBufferImageDescription()->id() == DEFAULT_IMAGE_DESCRIPTION->id();
|
||||||
|
auto shader = useShader(getShaderVariant(SH_FRAG_SHADOW, skipCM ? 0 : SH_FEAT_CM | (IS_ICC ? SH_FEAT_ICC : SH_FEAT_TONEMAP | SH_FEAT_SDR_MOD)));
|
||||||
|
if (!skipCM)
|
||||||
|
passCMUniforms(shader, DEFAULT_IMAGE_DESCRIPTION);
|
||||||
|
|
||||||
shader->setUniformMatrix3fv(SHADER_PROJ, 1, GL_TRUE, glMatrix.getMatrix());
|
shader->setUniformMatrix3fv(SHADER_PROJ, 1, GL_TRUE, glMatrix.getMatrix());
|
||||||
shader->setUniformFloat4(SHADER_COLOR, col.r, col.g, col.b, col.a * a);
|
shader->setUniformFloat4(SHADER_COLOR, col.r, col.g, col.b, col.a * a);
|
||||||
|
|
@ -3141,53 +3058,23 @@ bool CHyprOpenGLImpl::explicitSyncSupported() {
|
||||||
return m_exts.EGL_ANDROID_native_fence_sync_ext;
|
return m_exts.EGL_ANDROID_native_fence_sync_ext;
|
||||||
}
|
}
|
||||||
|
|
||||||
WP<CShader> CHyprOpenGLImpl::getSurfaceShader(uint8_t features) {
|
WP<CShader> CHyprOpenGLImpl::getShaderVariant(ePreparedFragmentShader frag, ShaderFeatureFlags features) {
|
||||||
if (!m_shaders->fragVariants.contains(features)) {
|
if (!m_shaders->fragVariants[frag].contains(features)) {
|
||||||
|
|
||||||
auto shader = makeShared<CShader>();
|
auto shader = makeShared<CShader>();
|
||||||
auto includes = m_includes;
|
|
||||||
includes["get_rgb_pixel.glsl"] = includes[features & SH_FEAT_RGBA ? "get_rgba_pixel.glsl" : "get_rgbx_pixel.glsl"];
|
|
||||||
if (!(features & SH_FEAT_DISCARD)) {
|
|
||||||
includes["discard.glsl"] = "";
|
|
||||||
includes["do_discard.glsl"] = "";
|
|
||||||
}
|
|
||||||
if (!(features & SH_FEAT_TINT)) {
|
|
||||||
includes["tint.glsl"] = "";
|
|
||||||
includes["do_tint.glsl"] = "";
|
|
||||||
}
|
|
||||||
if (!(features & SH_FEAT_ROUNDING)) {
|
|
||||||
includes["rounding.glsl"] = "";
|
|
||||||
includes["do_rounding.glsl"] = "";
|
|
||||||
}
|
|
||||||
if (!(features & SH_FEAT_CM)) {
|
|
||||||
includes["surface_CM.glsl"] = "";
|
|
||||||
includes["CM.glsl"] = "";
|
|
||||||
includes["do_CM.glsl"] = "";
|
|
||||||
}
|
|
||||||
if (!(features & SH_FEAT_TONEMAP)) {
|
|
||||||
includes["tonemap.glsl"] = "";
|
|
||||||
includes["do_tonemap.glsl"] = "";
|
|
||||||
}
|
|
||||||
if (!(features & SH_FEAT_SDR_MOD)) {
|
|
||||||
includes["sdr_mod.glsl"] = "";
|
|
||||||
includes["do_sdr_mod.glsl"] = "";
|
|
||||||
}
|
|
||||||
if (!(features & SH_FEAT_TONEMAP || features & SH_FEAT_SDR_MOD))
|
|
||||||
includes["primaries_xyz.glsl"] = includes["primaries_xyz_const.glsl"];
|
|
||||||
|
|
||||||
Log::logger->log(Log::INFO, "getSurfaceShader: compiling feature set {}", features);
|
Log::logger->log(Log::INFO, "compiling feature set {} for {}", features, FRAG_SHADERS[frag]);
|
||||||
const auto fragSrc = processShader("surface.frag", includes, MAX_INCLUDE_DEPTH);
|
|
||||||
if (shader->createProgram(m_shaders->TEXVERTSRC, fragSrc, true, true)) {
|
const auto fragSrc = g_pShaderLoader->getVariantSource(frag, features);
|
||||||
m_shaders->fragVariants[features] = shader;
|
|
||||||
|
if (!shader->createProgram(m_shaders->TEXVERTSRC, fragSrc, true, true))
|
||||||
|
Log::logger->log(Log::ERR, "shader features {} failed for {}", features, FRAG_SHADERS[frag]);
|
||||||
|
|
||||||
|
m_shaders->fragVariants[frag][features] = shader;
|
||||||
return shader;
|
return shader;
|
||||||
} else {
|
|
||||||
Log::logger->log(Log::ERR, "getSurfaceShader failed for {}. Falling back to old branching", features);
|
|
||||||
m_shaders->fragVariants[features] = nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(m_shaders->fragVariants[features]);
|
ASSERT(m_shaders->fragVariants[frag][features]);
|
||||||
return m_shaders->fragVariants[features];
|
return m_shaders->fragVariants[frag][features];
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<SDRMFormat> CHyprOpenGLImpl::getDRMFormats() {
|
std::vector<SDRMFormat> CHyprOpenGLImpl::getDRMFormats() {
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@
|
||||||
|
|
||||||
#include "../debug/TracyDefines.hpp"
|
#include "../debug/TracyDefines.hpp"
|
||||||
#include "../protocols/core/Compositor.hpp"
|
#include "../protocols/core/Compositor.hpp"
|
||||||
|
#include "render/ShaderLoader.hpp"
|
||||||
|
|
||||||
struct gbm_device;
|
struct gbm_device;
|
||||||
class CHyprRenderer;
|
class CHyprRenderer;
|
||||||
|
|
@ -87,54 +88,23 @@ enum eMonitorExtraRenderFBs : uint8_t {
|
||||||
FB_MONITOR_RENDER_EXTRA_BLUR,
|
FB_MONITOR_RENDER_EXTRA_BLUR,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ePreparedFragmentShader : uint8_t {
|
|
||||||
SH_FRAG_QUAD = 0,
|
|
||||||
SH_FRAG_PASSTHRURGBA,
|
|
||||||
SH_FRAG_MATTE,
|
|
||||||
SH_FRAG_EXT,
|
|
||||||
SH_FRAG_BLUR1,
|
|
||||||
SH_FRAG_BLUR2,
|
|
||||||
SH_FRAG_CM_BLURPREPARE,
|
|
||||||
SH_FRAG_BLURPREPARE,
|
|
||||||
SH_FRAG_BLURFINISH,
|
|
||||||
SH_FRAG_SHADOW,
|
|
||||||
SH_FRAG_CM_BORDER1,
|
|
||||||
SH_FRAG_BORDER1,
|
|
||||||
SH_FRAG_GLITCH,
|
|
||||||
|
|
||||||
SH_FRAG_LAST,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ePreparedFragmentShaderFeature : uint8_t {
|
|
||||||
SH_FEAT_UNKNOWN = 0, // all features just in case
|
|
||||||
|
|
||||||
SH_FEAT_RGBA = (1 << 0), // RGBA/RGBX texture sampling
|
|
||||||
SH_FEAT_DISCARD = (1 << 1), // RGBA/RGBX texture sampling
|
|
||||||
SH_FEAT_TINT = (1 << 2), // uniforms: tint; condition: applyTint
|
|
||||||
SH_FEAT_ROUNDING = (1 << 3), // uniforms: radius, roundingPower, topLeft, fullSize; condition: radius > 0
|
|
||||||
SH_FEAT_CM = (1 << 4), // uniforms: srcTFRange, dstTFRange, srcRefLuminance, convertMatrix; condition: !skipCM
|
|
||||||
SH_FEAT_TONEMAP = (1 << 5), // uniforms: maxLuminance, dstMaxLuminance, dstRefLuminance; condition: maxLuminance < dstMaxLuminance * 1.01
|
|
||||||
SH_FEAT_SDR_MOD = (1 << 6), // uniforms: sdrSaturation, sdrBrightnessMultiplier; condition: SDR <-> HDR && (sdrSaturation != 1 || sdrBrightnessMultiplier != 1)
|
|
||||||
|
|
||||||
// uniforms: targetPrimariesXYZ; condition: SH_FEAT_TONEMAP || SH_FEAT_SDR_MOD
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SFragShaderDesc {
|
struct SFragShaderDesc {
|
||||||
ePreparedFragmentShader id;
|
Render::ePreparedFragmentShader id;
|
||||||
const char* file;
|
const char* file;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SPreparedShaders {
|
struct SPreparedShaders {
|
||||||
SPreparedShaders() {
|
// SPreparedShaders() {
|
||||||
for (auto& f : frag) {
|
// for (auto& f : frag) {
|
||||||
f = makeShared<CShader>();
|
// f = makeShared<CShader>();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
std::string TEXVERTSRC;
|
std::string TEXVERTSRC;
|
||||||
std::string TEXVERTSRC320;
|
std::string TEXVERTSRC320;
|
||||||
std::array<SP<CShader>, SH_FRAG_LAST> frag;
|
// std::array<SP<CShader>, SH_FRAG_LAST> frag;
|
||||||
std::map<uint8_t, SP<CShader>> fragVariants;
|
// std::map<uint8_t, SP<CShader>> fragVariants;
|
||||||
|
std::array<std::map<Render::ShaderFeatureFlags, SP<CShader>>, Render::SH_FRAG_LAST> fragVariants;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SMonitorRenderData {
|
struct SMonitorRenderData {
|
||||||
|
|
@ -242,6 +212,8 @@ class CHyprOpenGLImpl {
|
||||||
bool cmBackToSRGB = false;
|
bool cmBackToSRGB = false;
|
||||||
bool noCM = false;
|
bool noCM = false;
|
||||||
bool finalMonitorCM = false;
|
bool finalMonitorCM = false;
|
||||||
|
SP<CMonitor> cmBackToSRGBSource;
|
||||||
|
SP<CTexture> blurredBG;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SBorderRenderData {
|
struct SBorderRenderData {
|
||||||
|
|
@ -316,18 +288,15 @@ class CHyprOpenGLImpl {
|
||||||
std::vector<uint64_t> getDRMFormatModifiers(DRMFormat format);
|
std::vector<uint64_t> getDRMFormatModifiers(DRMFormat format);
|
||||||
EGLImageKHR createEGLImage(const Aquamarine::SDMABUFAttrs& attrs);
|
EGLImageKHR createEGLImage(const Aquamarine::SDMABUFAttrs& attrs);
|
||||||
|
|
||||||
bool initShaders();
|
bool initShaders(const std::string& path = "");
|
||||||
|
|
||||||
WP<CShader> useShader(WP<CShader> prog);
|
WP<CShader> useShader(WP<CShader> prog);
|
||||||
|
|
||||||
void ensureLockTexturesRendered(bool load);
|
|
||||||
|
|
||||||
bool explicitSyncSupported();
|
bool explicitSyncSupported();
|
||||||
WP<CShader> getSurfaceShader(uint8_t features);
|
WP<CShader> getShaderVariant(Render::ePreparedFragmentShader frag, Render::ShaderFeatureFlags features = 0);
|
||||||
|
|
||||||
bool m_shadersInitialized = false;
|
bool m_shadersInitialized = false;
|
||||||
SP<SPreparedShaders> m_shaders;
|
SP<SPreparedShaders> m_shaders;
|
||||||
std::map<std::string, std::string> m_includes;
|
|
||||||
|
|
||||||
SCurrentRenderData m_renderData;
|
SCurrentRenderData m_renderData;
|
||||||
|
|
||||||
|
|
@ -431,6 +400,7 @@ class CHyprOpenGLImpl {
|
||||||
void initEGL(bool gbm);
|
void initEGL(bool gbm);
|
||||||
EGLDeviceEXT eglDeviceFromDRMFD(int drmFD);
|
EGLDeviceEXT eglDeviceFromDRMFD(int drmFD);
|
||||||
void initAssets();
|
void initAssets();
|
||||||
|
void ensureLockTexturesRendered(bool load);
|
||||||
void initMissingAssetTexture();
|
void initMissingAssetTexture();
|
||||||
void requestBackgroundResource();
|
void requestBackgroundResource();
|
||||||
|
|
||||||
|
|
@ -454,6 +424,8 @@ class CHyprOpenGLImpl {
|
||||||
void renderRectInternal(const CBox&, const CHyprColor&, const SRectRenderData& data);
|
void renderRectInternal(const CBox&, const CHyprColor&, const SRectRenderData& data);
|
||||||
void renderRectWithBlurInternal(const CBox&, const CHyprColor&, const SRectRenderData& data);
|
void renderRectWithBlurInternal(const CBox&, const CHyprColor&, const SRectRenderData& data);
|
||||||
void renderRectWithDamageInternal(const CBox&, const CHyprColor&, const SRectRenderData& data);
|
void renderRectWithDamageInternal(const CBox&, const CHyprColor&, const SRectRenderData& data);
|
||||||
|
WP<CShader> renderToOutputInternal();
|
||||||
|
WP<CShader> renderToFBInternal(const STextureRenderData& data, eTextureType texType, const CBox& newBox);
|
||||||
void renderTextureInternal(SP<CTexture>, const CBox&, const STextureRenderData& data);
|
void renderTextureInternal(SP<CTexture>, const CBox&, const STextureRenderData& data);
|
||||||
void renderTextureWithBlurInternal(SP<CTexture>, const CBox&, const STextureRenderData& data);
|
void renderTextureWithBlurInternal(SP<CTexture>, const CBox&, const STextureRenderData& data);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ CRenderbuffer::CRenderbuffer(SP<Aquamarine::IBuffer> buffer, uint32_t format) :
|
||||||
glGenFramebuffers(1, &m_framebuffer.m_fb);
|
glGenFramebuffers(1, &m_framebuffer.m_fb);
|
||||||
m_framebuffer.m_fbAllocated = true;
|
m_framebuffer.m_fbAllocated = true;
|
||||||
m_framebuffer.m_size = buffer->size;
|
m_framebuffer.m_size = buffer->size;
|
||||||
|
m_framebuffer.m_drmFormat = dma.format;
|
||||||
m_framebuffer.bind();
|
m_framebuffer.bind();
|
||||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_rbo);
|
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_rbo);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@
|
||||||
#include "../event/EventBus.hpp"
|
#include "../event/EventBus.hpp"
|
||||||
#include "helpers/CursorShapes.hpp"
|
#include "helpers/CursorShapes.hpp"
|
||||||
#include "helpers/Monitor.hpp"
|
#include "helpers/Monitor.hpp"
|
||||||
|
#include "helpers/cm/ColorManagement.hpp"
|
||||||
#include "pass/TexPassElement.hpp"
|
#include "pass/TexPassElement.hpp"
|
||||||
#include "pass/ClearPassElement.hpp"
|
#include "pass/ClearPassElement.hpp"
|
||||||
#include "pass/RectPassElement.hpp"
|
#include "pass/RectPassElement.hpp"
|
||||||
|
|
@ -41,7 +42,6 @@
|
||||||
#include "../protocols/ColorManagement.hpp"
|
#include "../protocols/ColorManagement.hpp"
|
||||||
#include "../protocols/types/ContentType.hpp"
|
#include "../protocols/types/ContentType.hpp"
|
||||||
#include "../helpers/MiscFunctions.hpp"
|
#include "../helpers/MiscFunctions.hpp"
|
||||||
#include "../event/EventBus.hpp"
|
|
||||||
#include "render/OpenGL.hpp"
|
#include "render/OpenGL.hpp"
|
||||||
|
|
||||||
#include <hyprutils/utils/ScopeGuard.hpp>
|
#include <hyprutils/utils/ScopeGuard.hpp>
|
||||||
|
|
@ -1260,6 +1260,79 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SP<CWLSurfaceResour
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool isSDR2HDR(const NColorManagement::SImageDescription& imageDescription, const NColorManagement::SImageDescription& targetImageDescription) {
|
||||||
|
// might be too strict
|
||||||
|
return (imageDescription.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_SRGB ||
|
||||||
|
imageDescription.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22) &&
|
||||||
|
(targetImageDescription.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ ||
|
||||||
|
targetImageDescription.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_HLG);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isHDR2SDR(const NColorManagement::SImageDescription& imageDescription, const NColorManagement::SImageDescription& targetImageDescription) {
|
||||||
|
// might be too strict
|
||||||
|
return (imageDescription.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ ||
|
||||||
|
imageDescription.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_HLG) &&
|
||||||
|
(targetImageDescription.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_SRGB ||
|
||||||
|
targetImageDescription.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22);
|
||||||
|
}
|
||||||
|
|
||||||
|
SCMSettings CHyprRenderer::getCMSettings(const NColorManagement::PImageDescription imageDescription, const NColorManagement::PImageDescription targetImageDescription,
|
||||||
|
SP<CWLSurfaceResource> surface, bool modifySDR, float sdrMinLuminance, int sdrMaxLuminance) {
|
||||||
|
const auto sdrEOTF = NTransferFunction::fromConfig();
|
||||||
|
NColorManagement::eTransferFunction srcTF;
|
||||||
|
|
||||||
|
auto& m_renderData = g_pHyprOpenGL->m_renderData;
|
||||||
|
if (m_renderData.surface.valid()) {
|
||||||
|
if (m_renderData.surface->m_colorManagement.valid()) {
|
||||||
|
if (sdrEOTF == NTransferFunction::TF_FORCED_GAMMA22 && imageDescription->value().transferFunction == NColorManagement::eTransferFunction::CM_TRANSFER_FUNCTION_SRGB)
|
||||||
|
srcTF = NColorManagement::eTransferFunction::CM_TRANSFER_FUNCTION_GAMMA22;
|
||||||
|
else
|
||||||
|
srcTF = imageDescription->value().transferFunction;
|
||||||
|
} else if (sdrEOTF == NTransferFunction::TF_SRGB)
|
||||||
|
srcTF = NColorManagement::eTransferFunction::CM_TRANSFER_FUNCTION_SRGB;
|
||||||
|
else if (sdrEOTF == NTransferFunction::TF_GAMMA22 || sdrEOTF == NTransferFunction::TF_FORCED_GAMMA22)
|
||||||
|
srcTF = NColorManagement::eTransferFunction::CM_TRANSFER_FUNCTION_GAMMA22;
|
||||||
|
else
|
||||||
|
srcTF = imageDescription->value().transferFunction;
|
||||||
|
} else
|
||||||
|
srcTF = imageDescription->value().transferFunction;
|
||||||
|
|
||||||
|
const bool needsSDRmod = modifySDR && isSDR2HDR(imageDescription->value(), targetImageDescription->value());
|
||||||
|
const bool needsHDRmod = !needsSDRmod && isHDR2SDR(imageDescription->value(), targetImageDescription->value());
|
||||||
|
const float maxLuminance = needsHDRmod ?
|
||||||
|
imageDescription->value().getTFMaxLuminance(-1) :
|
||||||
|
(imageDescription->value().luminances.max > 0 ? imageDescription->value().luminances.max : imageDescription->value().luminances.reference);
|
||||||
|
const auto dstMaxLuminance = targetImageDescription->value().luminances.max > 0 ? targetImageDescription->value().luminances.max : 10000;
|
||||||
|
|
||||||
|
auto matrix = imageDescription->getPrimaries()->convertMatrix(targetImageDescription->getPrimaries());
|
||||||
|
auto toXYZ = targetImageDescription->getPrimaries()->value().toXYZ();
|
||||||
|
|
||||||
|
const bool needsMod = (imageDescription->value().transferFunction == CM_TRANSFER_FUNCTION_SRGB || imageDescription->value().transferFunction == CM_TRANSFER_FUNCTION_GAMMA22) &&
|
||||||
|
targetImageDescription->value().transferFunction == CM_TRANSFER_FUNCTION_ST2084_PQ &&
|
||||||
|
((m_renderData.pMonitor->m_sdrSaturation > 0 && m_renderData.pMonitor->m_sdrSaturation != 1.0f) ||
|
||||||
|
(m_renderData.pMonitor->m_sdrBrightness > 0 && m_renderData.pMonitor->m_sdrBrightness != 1.0f));
|
||||||
|
|
||||||
|
return {
|
||||||
|
.sourceTF = srcTF,
|
||||||
|
.targetTF = targetImageDescription->value().transferFunction,
|
||||||
|
.srcTFRange = {.min = imageDescription->value().getTFMinLuminance(needsSDRmod ? sdrMinLuminance : -1),
|
||||||
|
.max = imageDescription->value().getTFMaxLuminance(needsSDRmod ? sdrMaxLuminance : -1)},
|
||||||
|
.dstTFRange = {.min = targetImageDescription->value().getTFMinLuminance(needsSDRmod ? sdrMinLuminance : -1),
|
||||||
|
.max = targetImageDescription->value().getTFMaxLuminance(needsSDRmod ? sdrMaxLuminance : -1)},
|
||||||
|
.srcRefLuminance = imageDescription->value().luminances.reference,
|
||||||
|
.dstRefLuminance = targetImageDescription->value().luminances.reference,
|
||||||
|
.convertMatrix = matrix.mat(),
|
||||||
|
|
||||||
|
.needsTonemap = maxLuminance >= dstMaxLuminance * 1.01,
|
||||||
|
.maxLuminance = maxLuminance * targetImageDescription->value().luminances.reference / imageDescription->value().luminances.reference,
|
||||||
|
.dstMaxLuminance = dstMaxLuminance,
|
||||||
|
.dstPrimaries2XYZ = toXYZ.mat(),
|
||||||
|
.needsSDRmod = needsMod,
|
||||||
|
.sdrSaturation = needsSDRmod && m_renderData.pMonitor->m_sdrSaturation > 0 ? m_renderData.pMonitor->m_sdrSaturation : 1.0f,
|
||||||
|
.sdrBrightnessMultiplier = needsSDRmod && m_renderData.pMonitor->m_sdrBrightness > 0 ? m_renderData.pMonitor->m_sdrBrightness : 1.0f,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
void CHyprRenderer::renderMonitor(PHLMONITOR pMonitor, bool commit) {
|
void CHyprRenderer::renderMonitor(PHLMONITOR pMonitor, bool commit) {
|
||||||
static std::chrono::high_resolution_clock::time_point renderStart = std::chrono::high_resolution_clock::now();
|
static std::chrono::high_resolution_clock::time_point renderStart = std::chrono::high_resolution_clock::now();
|
||||||
static std::chrono::high_resolution_clock::time_point renderStartOverlay = std::chrono::high_resolution_clock::now();
|
static std::chrono::high_resolution_clock::time_point renderStartOverlay = std::chrono::high_resolution_clock::now();
|
||||||
|
|
@ -2200,10 +2273,8 @@ std::tuple<float, float, float> CHyprRenderer::getRenderTimes(PHLMONITOR pMonito
|
||||||
float maxRenderTime = 0;
|
float maxRenderTime = 0;
|
||||||
float minRenderTime = 9999;
|
float minRenderTime = 9999;
|
||||||
for (auto const& rt : POVERLAY->m_lastRenderTimes) {
|
for (auto const& rt : POVERLAY->m_lastRenderTimes) {
|
||||||
if (rt > maxRenderTime)
|
maxRenderTime = std::max(rt, maxRenderTime);
|
||||||
maxRenderTime = rt;
|
minRenderTime = std::min(rt, minRenderTime);
|
||||||
if (rt < minRenderTime)
|
|
||||||
minRenderTime = rt;
|
|
||||||
avgRenderTime += rt;
|
avgRenderTime += rt;
|
||||||
}
|
}
|
||||||
avgRenderTime /= POVERLAY->m_lastRenderTimes.empty() ? 1 : POVERLAY->m_lastRenderTimes.size();
|
avgRenderTime /= POVERLAY->m_lastRenderTimes.empty() ? 1 : POVERLAY->m_lastRenderTimes.size();
|
||||||
|
|
@ -2706,6 +2777,16 @@ void CHyprRenderer::renderSnapshot(WP<Desktop::View::CPopup> popup) {
|
||||||
m_renderPass.add(makeUnique<CTexPassElement>(std::move(data)));
|
m_renderPass.add(makeUnique<CTexPassElement>(std::move(data)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NColorManagement::PImageDescription CHyprRenderer::workBufferImageDescription() {
|
||||||
|
const auto& m_renderData = g_pHyprOpenGL->m_renderData;
|
||||||
|
// TODO
|
||||||
|
// const bool IS_MONITOR_ICC = m_renderData.pMonitor->m_imageDescription.valid() && m_renderData.pMonitor->m_imageDescription->value().icc.present;
|
||||||
|
// const auto sdrEOTF = NTransferFunction::fromConfig(IS_MONITOR_ICC);
|
||||||
|
// const auto CHOSEN_SDR_EOTF = sdrEOTF != NTransferFunction::TF_SRGB ? NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22 : NColorManagement::CM_TRANSFER_FUNCTION_SRGB;
|
||||||
|
|
||||||
|
return m_renderData.pMonitor->m_imageDescription; //CImageDescription::from(NColorManagement::SImageDescription{.transferFunction = CHOSEN_SDR_EOTF});
|
||||||
|
}
|
||||||
|
|
||||||
bool CHyprRenderer::shouldBlur(PHLLS ls) {
|
bool CHyprRenderer::shouldBlur(PHLLS ls) {
|
||||||
if (m_bRenderingSnapshot)
|
if (m_bRenderingSnapshot)
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -2729,3 +2810,7 @@ bool CHyprRenderer::shouldBlur(WP<Desktop::View::CPopup> p) {
|
||||||
|
|
||||||
return *PBLURPOPUPS && *PBLUR;
|
return *PBLURPOPUPS && *PBLUR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CHyprRenderer::reloadShaders(const std::string& path) {
|
||||||
|
return g_pHyprOpenGL->initShaders(path);
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../defines.hpp"
|
#include "../defines.hpp"
|
||||||
|
#include <hyprgraphics/color/Color.hpp>
|
||||||
|
#include <hyprutils/math/Box.hpp>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
#include <optional>
|
||||||
#include "../helpers/Monitor.hpp"
|
#include "../helpers/Monitor.hpp"
|
||||||
#include "../desktop/view/LayerSurface.hpp"
|
#include "../desktop/view/LayerSurface.hpp"
|
||||||
#include "OpenGL.hpp"
|
#include "OpenGL.hpp"
|
||||||
|
|
@ -10,12 +13,21 @@
|
||||||
#include "../helpers/math/Math.hpp"
|
#include "../helpers/math/Math.hpp"
|
||||||
#include "../helpers/time/Time.hpp"
|
#include "../helpers/time/Time.hpp"
|
||||||
#include "../../protocols/cursor-shape-v1.hpp"
|
#include "../../protocols/cursor-shape-v1.hpp"
|
||||||
|
#include "helpers/cm/ColorManagement.hpp"
|
||||||
|
|
||||||
struct SMonitorRule;
|
struct SMonitorRule;
|
||||||
class CWorkspace;
|
class CWorkspace;
|
||||||
class CInputPopup;
|
class CInputPopup;
|
||||||
class IHLBuffer;
|
class IHLBuffer;
|
||||||
class CEventLoopTimer;
|
class CEventLoopTimer;
|
||||||
|
|
||||||
|
const std::vector<const char*> ASSET_PATHS = {
|
||||||
|
#ifdef DATAROOTDIR
|
||||||
|
DATAROOTDIR,
|
||||||
|
#endif
|
||||||
|
"/usr/share",
|
||||||
|
"/usr/local/share",
|
||||||
|
};
|
||||||
class CToplevelExportProtocolManager;
|
class CToplevelExportProtocolManager;
|
||||||
class CInputManager;
|
class CInputManager;
|
||||||
struct SSessionLockSurface;
|
struct SSessionLockSurface;
|
||||||
|
|
@ -48,6 +60,29 @@ struct SRenderWorkspaceUntilData {
|
||||||
PHLWINDOW w;
|
PHLWINDOW w;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct STFRange {
|
||||||
|
float min = 0;
|
||||||
|
float max = 80;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SCMSettings {
|
||||||
|
NColorManagement::eTransferFunction sourceTF = NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22;
|
||||||
|
NColorManagement::eTransferFunction targetTF = NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22;
|
||||||
|
STFRange srcTFRange;
|
||||||
|
STFRange dstTFRange;
|
||||||
|
float srcRefLuminance = 80;
|
||||||
|
float dstRefLuminance = 80;
|
||||||
|
std::array<std::array<double, 3>, 3> convertMatrix;
|
||||||
|
|
||||||
|
bool needsTonemap = false;
|
||||||
|
float maxLuminance = 80;
|
||||||
|
float dstMaxLuminance = 80;
|
||||||
|
std::array<std::array<double, 3>, 3> dstPrimaries2XYZ;
|
||||||
|
bool needsSDRmod = false;
|
||||||
|
float sdrSaturation = 1.0;
|
||||||
|
float sdrBrightnessMultiplier = 1.0;
|
||||||
|
};
|
||||||
|
|
||||||
class CHyprRenderer {
|
class CHyprRenderer {
|
||||||
public:
|
public:
|
||||||
CHyprRenderer();
|
CHyprRenderer();
|
||||||
|
|
@ -89,6 +124,9 @@ class CHyprRenderer {
|
||||||
void renderSnapshot(PHLLS);
|
void renderSnapshot(PHLLS);
|
||||||
void renderSnapshot(WP<Desktop::View::CPopup>);
|
void renderSnapshot(WP<Desktop::View::CPopup>);
|
||||||
|
|
||||||
|
//
|
||||||
|
NColorManagement::PImageDescription workBufferImageDescription();
|
||||||
|
|
||||||
// if RENDER_MODE_NORMAL, provided damage will be written to.
|
// if RENDER_MODE_NORMAL, provided damage will be written to.
|
||||||
// otherwise, it will be the one used.
|
// otherwise, it will be the one used.
|
||||||
bool beginRender(PHLMONITOR pMonitor, CRegion& damage, eRenderMode mode = RENDER_MODE_NORMAL, SP<IHLBuffer> buffer = {}, CFramebuffer* fb = nullptr, bool simple = false);
|
bool beginRender(PHLMONITOR pMonitor, CRegion& damage, eRenderMode mode = RENDER_MODE_NORMAL, SP<IHLBuffer> buffer = {}, CFramebuffer* fb = nullptr, bool simple = false);
|
||||||
|
|
@ -121,6 +159,10 @@ class CHyprRenderer {
|
||||||
|
|
||||||
CRenderPass m_renderPass = {};
|
CRenderPass m_renderPass = {};
|
||||||
|
|
||||||
|
SCMSettings getCMSettings(const NColorManagement::PImageDescription imageDescription, const NColorManagement::PImageDescription targetImageDescription,
|
||||||
|
SP<CWLSurfaceResource> surface = nullptr, bool modifySDR = false, float sdrMinLuminance = -1.0f, int sdrMaxLuminance = -1);
|
||||||
|
bool reloadShaders(const std::string& path = "");
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void arrangeLayerArray(PHLMONITOR, const std::vector<PHLLSREF>&, bool, CBox*);
|
void arrangeLayerArray(PHLMONITOR, const std::vector<PHLLSREF>&, bool, CBox*);
|
||||||
void renderWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, const Time::steady_tp& now, const CBox& geometry);
|
void renderWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, const Time::steady_tp& now, const CBox& geometry);
|
||||||
|
|
|
||||||
|
|
@ -139,11 +139,13 @@ void CShader::getUniformLocations() {
|
||||||
m_uniformLocations[SHADER_SDR_SATURATION] = getUniform("sdrSaturation");
|
m_uniformLocations[SHADER_SDR_SATURATION] = getUniform("sdrSaturation");
|
||||||
m_uniformLocations[SHADER_SDR_BRIGHTNESS] = getUniform("sdrBrightnessMultiplier");
|
m_uniformLocations[SHADER_SDR_BRIGHTNESS] = getUniform("sdrBrightnessMultiplier");
|
||||||
m_uniformLocations[SHADER_CONVERT_MATRIX] = getUniform("convertMatrix");
|
m_uniformLocations[SHADER_CONVERT_MATRIX] = getUniform("convertMatrix");
|
||||||
m_uniformLocations[SHADER_USE_ICC] = getUniform("useIcc");
|
|
||||||
m_uniformLocations[SHADER_LUT_3D] = getUniform("iccLut3D");
|
m_uniformLocations[SHADER_LUT_3D] = getUniform("iccLut3D");
|
||||||
m_uniformLocations[SHADER_LUT_SIZE] = getUniform("iccLutSize");
|
m_uniformLocations[SHADER_LUT_SIZE] = getUniform("iccLutSize");
|
||||||
//
|
//
|
||||||
m_uniformLocations[SHADER_TEX] = getUniform("tex");
|
m_uniformLocations[SHADER_TEX] = getUniform("tex");
|
||||||
|
m_uniformLocations[SHADER_BLURRED_BG] = getUniform("blurredBG");
|
||||||
|
m_uniformLocations[SHADER_UV_SIZE] = getUniform("uvSize");
|
||||||
|
m_uniformLocations[SHADER_UV_OFFSET] = getUniform("uvOffset");
|
||||||
m_uniformLocations[SHADER_ALPHA] = getUniform("alpha");
|
m_uniformLocations[SHADER_ALPHA] = getUniform("alpha");
|
||||||
m_uniformLocations[SHADER_POS_ATTRIB] = getAttrib("pos");
|
m_uniformLocations[SHADER_POS_ATTRIB] = getAttrib("pos");
|
||||||
m_uniformLocations[SHADER_TEX_ATTRIB] = getAttrib("texcoord");
|
m_uniformLocations[SHADER_TEX_ATTRIB] = getAttrib("texcoord");
|
||||||
|
|
|
||||||
|
|
@ -74,9 +74,11 @@ enum eShaderUniform : uint8_t {
|
||||||
SHADER_POINTER_INACTIVE_TIMEOUT,
|
SHADER_POINTER_INACTIVE_TIMEOUT,
|
||||||
SHADER_POINTER_LAST_ACTIVE,
|
SHADER_POINTER_LAST_ACTIVE,
|
||||||
SHADER_POINTER_SIZE,
|
SHADER_POINTER_SIZE,
|
||||||
SHADER_USE_ICC,
|
|
||||||
SHADER_LUT_3D,
|
SHADER_LUT_3D,
|
||||||
SHADER_LUT_SIZE,
|
SHADER_LUT_SIZE,
|
||||||
|
SHADER_BLURRED_BG,
|
||||||
|
SHADER_UV_SIZE,
|
||||||
|
SHADER_UV_OFFSET,
|
||||||
|
|
||||||
SHADER_LAST,
|
SHADER_LAST,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
176
src/render/ShaderLoader.cpp
Normal file
176
src/render/ShaderLoader.cpp
Normal file
|
|
@ -0,0 +1,176 @@
|
||||||
|
#include "ShaderLoader.hpp"
|
||||||
|
#include <format>
|
||||||
|
#include <hyprutils/memory/Casts.hpp>
|
||||||
|
#include <hyprutils/memory/UniquePtr.hpp>
|
||||||
|
#include <hyprutils/string/String.hpp>
|
||||||
|
#include <hyprutils/path/Path.hpp>
|
||||||
|
#include "../debug/log/Logger.hpp"
|
||||||
|
#include "shaders/Shaders.hpp"
|
||||||
|
#include "../helpers/fs/FsUtils.hpp"
|
||||||
|
#include "Renderer.hpp"
|
||||||
|
#include <glslang/Public/resource_limits_c.h>
|
||||||
|
#include <string>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
using namespace Render;
|
||||||
|
|
||||||
|
CShaderLoader::CShaderLoader(const std::vector<std::string> includes, const std::array<std::string, SH_FRAG_LAST>& frags, const std::string shaderPath) : m_shaderPath(shaderPath) {
|
||||||
|
m_callbacks = glsl_include_callbacks_t{
|
||||||
|
.include_local =
|
||||||
|
[](void* ctx, const char* header_name, const char* includer_name, size_t include_depth) {
|
||||||
|
auto shaderLoader = sc<CShaderLoader*>(ctx);
|
||||||
|
auto res = new glsl_include_result_t;
|
||||||
|
if (shaderLoader->m_overrideDefines.length() && std::string{header_name} == "defines.h") {
|
||||||
|
res->header_name = header_name;
|
||||||
|
res->header_data = shaderLoader->m_overrideDefines.c_str();
|
||||||
|
res->header_length = shaderLoader->m_overrideDefines.length();
|
||||||
|
} else if (shaderLoader->includes().contains(header_name)) {
|
||||||
|
res->header_name = header_name;
|
||||||
|
res->header_data = shaderLoader->includes().at(header_name).c_str();
|
||||||
|
res->header_length = shaderLoader->includes().at(header_name).length();
|
||||||
|
} else {
|
||||||
|
res->header_name = nullptr;
|
||||||
|
res->header_data = nullptr;
|
||||||
|
res->header_length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
shaderLoader->m_includeResults.push_back(res);
|
||||||
|
return res;
|
||||||
|
},
|
||||||
|
.free_include_result =
|
||||||
|
[](void* ctx, glsl_include_result_t* result) {
|
||||||
|
auto shaderLoader = sc<CShaderLoader*>(ctx);
|
||||||
|
std::erase(shaderLoader->m_includeResults, result);
|
||||||
|
delete result;
|
||||||
|
return 0;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const auto& inc : includes) {
|
||||||
|
include(inc);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ranges::transform(frags, m_fragFiles.begin(), [&](const auto& filename) { return loadShader(filename); });
|
||||||
|
}
|
||||||
|
|
||||||
|
CShaderLoader::~CShaderLoader() {
|
||||||
|
// glslFreeIncludeResult should leave it empty by this point
|
||||||
|
for (const auto& res : m_includeResults) {
|
||||||
|
delete res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CShaderLoader::include(const std::string& filename) {
|
||||||
|
m_includes.insert({filename, loadShader(filename)});
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CShaderLoader::getDefines(ShaderFeatureFlags features) {
|
||||||
|
std::string res = "";
|
||||||
|
std::map<std::string, std::string> defines = {
|
||||||
|
{"USE_RGBA", features & SH_FEAT_RGBA ? "1" : "0"}, {"USE_DISCARD", features & SH_FEAT_DISCARD ? "1" : "0"}, {"USE_TINT", features & SH_FEAT_TINT ? "1" : "0"},
|
||||||
|
{"USE_ROUNDING", features & SH_FEAT_ROUNDING ? "1" : "0"}, {"USE_CM", features & SH_FEAT_CM ? "1" : "0"}, {"USE_TONEMAP", features & SH_FEAT_TONEMAP ? "1" : "0"},
|
||||||
|
{"USE_SDR_MOD", features & SH_FEAT_SDR_MOD ? "1" : "0"}, {"USE_BLUR", features & SH_FEAT_BLUR ? "1" : "0"}, {"USE_ICC", features & SH_FEAT_ICC ? "1" : "0"},
|
||||||
|
};
|
||||||
|
for (const auto& [name, value] : defines) {
|
||||||
|
res += std::format("#define {} {}\n", name, value);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CShaderLoader::processSource(const std::string& source, glslang_stage_t stage) {
|
||||||
|
const glslang_input_t input = {
|
||||||
|
.language = GLSLANG_SOURCE_GLSL,
|
||||||
|
.stage = stage,
|
||||||
|
.client = GLSLANG_CLIENT_NONE,
|
||||||
|
.target_language = GLSLANG_TARGET_NONE,
|
||||||
|
.code = source.c_str(),
|
||||||
|
.default_version = 100,
|
||||||
|
.default_profile = GLSLANG_NO_PROFILE,
|
||||||
|
.force_default_version_and_profile = false,
|
||||||
|
.forward_compatible = false,
|
||||||
|
.messages = GLSLANG_MSG_DEFAULT_BIT,
|
||||||
|
.resource = glslang_default_resource(),
|
||||||
|
.callbacks = m_callbacks,
|
||||||
|
.callbacks_ctx = this,
|
||||||
|
};
|
||||||
|
|
||||||
|
glslang_shader_t* shader = glslang_shader_create(&input);
|
||||||
|
|
||||||
|
if (!glslang_shader_preprocess(shader, &input)) {
|
||||||
|
Log::logger->log(Log::ERR, "GLSL preprocessing failed");
|
||||||
|
Log::logger->log(Log::ERR, "{}", glslang_shader_get_info_log(shader));
|
||||||
|
Log::logger->log(Log::ERR, "{}", glslang_shader_get_info_debug_log(shader));
|
||||||
|
Log::logger->log(Log::ERR, "{}", input.code);
|
||||||
|
glslang_shader_delete(shader);
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream stream(glslang_shader_get_preprocessed_code(shader));
|
||||||
|
std::string code = "";
|
||||||
|
std::string line;
|
||||||
|
|
||||||
|
while (std::getline(stream, line)) {
|
||||||
|
if (!line.starts_with("#line "))
|
||||||
|
code += line + "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CShaderLoader::process(const std::string& filename) {
|
||||||
|
auto source = loadShader(filename);
|
||||||
|
return processSource(source, filename.ends_with(".vert") ? GLSLANG_STAGE_VERTEX : GLSLANG_STAGE_FRAGMENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CShaderLoader::process(const std::string& filename, const std::map<std::string, std::string>& defines) {
|
||||||
|
m_overrideDefines = "";
|
||||||
|
for (const auto& [name, value] : defines) {
|
||||||
|
m_overrideDefines += std::format("#define {} {}\n", name, value);
|
||||||
|
}
|
||||||
|
const auto& res = process(filename);
|
||||||
|
m_overrideDefines = "";
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CShaderLoader::getVariantSource(ePreparedFragmentShader frag, ShaderFeatureFlags features) {
|
||||||
|
static const auto PCM = CConfigValue<Hyprlang::INT>("render:cm_enabled");
|
||||||
|
if (!*PCM)
|
||||||
|
features &= ~(SH_FEAT_CM | SH_FEAT_TONEMAP | SH_FEAT_SDR_MOD);
|
||||||
|
|
||||||
|
if (!m_fragVariants[frag].contains(features)) {
|
||||||
|
ASSERT(m_fragFiles[frag].length());
|
||||||
|
m_overrideDefines = getDefines(features);
|
||||||
|
m_fragVariants[frag][features] = processSource(m_fragFiles[frag]);
|
||||||
|
m_overrideDefines = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_fragVariants[frag][features];
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::map<std::string, std::string>& CShaderLoader::includes() {
|
||||||
|
return m_includes;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO notify user if bundled shader is newer than ~/.config override
|
||||||
|
std::string CShaderLoader::loadShader(const std::string& filename) {
|
||||||
|
if (m_shaderPath.length()) {
|
||||||
|
std::filesystem::path path = m_shaderPath;
|
||||||
|
const auto src = NFsUtils::readFileAsString(path / filename);
|
||||||
|
if (src.has_value())
|
||||||
|
return src.value();
|
||||||
|
}
|
||||||
|
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));
|
||||||
|
}
|
||||||
77
src/render/ShaderLoader.hpp
Normal file
77
src/render/ShaderLoader.hpp
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <glslang/Include/glslang_c_interface.h>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include "../helpers/memory/Memory.hpp"
|
||||||
|
|
||||||
|
namespace Render {
|
||||||
|
enum ePreparedFragmentShaderFeature : uint16_t {
|
||||||
|
SH_FEAT_UNKNOWN = 0, // all features just in case
|
||||||
|
|
||||||
|
SH_FEAT_RGBA = (1 << 0), // RGBA/RGBX texture sampling
|
||||||
|
SH_FEAT_DISCARD = (1 << 1), // RGBA/RGBX texture sampling
|
||||||
|
SH_FEAT_TINT = (1 << 2), // uniforms: tint; condition: applyTint
|
||||||
|
SH_FEAT_ROUNDING = (1 << 3), // uniforms: radius, roundingPower, topLeft, fullSize; condition: radius > 0
|
||||||
|
SH_FEAT_CM = (1 << 4), // uniforms: srcTFRange, dstTFRange, srcRefLuminance, convertMatrix; condition: !skipCM
|
||||||
|
SH_FEAT_TONEMAP = (1 << 5), // uniforms: maxLuminance, dstMaxLuminance, dstRefLuminance; condition: maxLuminance < dstMaxLuminance * 1.01
|
||||||
|
SH_FEAT_SDR_MOD = (1 << 6), // uniforms: sdrSaturation, sdrBrightnessMultiplier; condition: SDR <-> HDR && (sdrSaturation != 1 || sdrBrightnessMultiplier != 1)
|
||||||
|
SH_FEAT_BLUR = (1 << 7), // condition: render:use_shader_blur_blend
|
||||||
|
SH_FEAT_ICC = (1 << 8), //
|
||||||
|
|
||||||
|
// uniforms: targetPrimariesXYZ; condition: SH_FEAT_TONEMAP || SH_FEAT_SDR_MOD
|
||||||
|
};
|
||||||
|
|
||||||
|
using ShaderFeatureFlags = uint16_t;
|
||||||
|
|
||||||
|
enum ePreparedFragmentShader : uint8_t {
|
||||||
|
SH_FRAG_QUAD = 0,
|
||||||
|
SH_FRAG_PASSTHRURGBA,
|
||||||
|
SH_FRAG_MATTE,
|
||||||
|
SH_FRAG_EXT,
|
||||||
|
SH_FRAG_BLUR1,
|
||||||
|
SH_FRAG_BLUR2,
|
||||||
|
SH_FRAG_BLURPREPARE,
|
||||||
|
SH_FRAG_BLURFINISH,
|
||||||
|
SH_FRAG_SHADOW,
|
||||||
|
SH_FRAG_SURFACE,
|
||||||
|
SH_FRAG_BORDER1,
|
||||||
|
SH_FRAG_GLITCH,
|
||||||
|
|
||||||
|
SH_FRAG_LAST,
|
||||||
|
};
|
||||||
|
|
||||||
|
class CShaderLoader {
|
||||||
|
public:
|
||||||
|
CShaderLoader(const std::vector<std::string> includes, const std::array<std::string, SH_FRAG_LAST>& frags, const std::string shaderPath = "");
|
||||||
|
~CShaderLoader();
|
||||||
|
|
||||||
|
void include(const std::string& filename);
|
||||||
|
std::string process(const std::string& filename);
|
||||||
|
std::string process(const std::string& filename, const std::map<std::string, std::string>& defines);
|
||||||
|
|
||||||
|
std::string getVariantSource(ePreparedFragmentShader frag, ShaderFeatureFlags features);
|
||||||
|
|
||||||
|
const std::map<std::string, std::string>& includes();
|
||||||
|
|
||||||
|
std::vector<glsl_include_result_t*> m_includeResults;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string loadShader(const std::string& filename);
|
||||||
|
std::string getDefines(ShaderFeatureFlags features);
|
||||||
|
std::string processSource(const std::string& source, glslang_stage_t stage = GLSLANG_STAGE_FRAGMENT);
|
||||||
|
|
||||||
|
//
|
||||||
|
std::string m_shaderPath;
|
||||||
|
std::array<std::string, SH_FRAG_LAST> m_fragFiles;
|
||||||
|
std::array<std::map<ShaderFeatureFlags, std::string>, SH_FRAG_LAST> m_fragVariants;
|
||||||
|
std::map<std::string, std::string> m_includes;
|
||||||
|
|
||||||
|
std::string m_overrideDefines;
|
||||||
|
glsl_include_callbacks_t m_callbacks;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline UP<CShaderLoader> g_pShaderLoader;
|
||||||
|
}
|
||||||
|
|
@ -1,306 +1,27 @@
|
||||||
|
#ifndef ALLOW_INCLUDES
|
||||||
|
#define ALLOW_INCLUDES
|
||||||
|
#extension GL_ARB_shading_language_include : enable
|
||||||
|
#endif
|
||||||
|
#include "cm_helpers.glsl"
|
||||||
|
|
||||||
uniform vec2 srcTFRange;
|
uniform vec2 srcTFRange;
|
||||||
uniform vec2 dstTFRange;
|
uniform vec2 dstTFRange;
|
||||||
|
|
||||||
uniform float srcRefLuminance;
|
uniform float srcRefLuminance;
|
||||||
uniform mat3 convertMatrix;
|
uniform mat3 convertMatrix;
|
||||||
|
|
||||||
#include "sdr_mod.glsl"
|
#if USE_ICC
|
||||||
|
|
||||||
uniform int useIcc;
|
|
||||||
uniform highp sampler3D iccLut3D;
|
uniform highp sampler3D iccLut3D;
|
||||||
uniform float iccLutSize;
|
uniform float iccLutSize;
|
||||||
|
#endif
|
||||||
|
|
||||||
//enum eTransferFunction
|
#if USE_SDR_MOD
|
||||||
#define CM_TRANSFER_FUNCTION_BT1886 1
|
uniform float sdrSaturation;
|
||||||
#define CM_TRANSFER_FUNCTION_GAMMA22 2
|
uniform float sdrBrightnessMultiplier;
|
||||||
#define CM_TRANSFER_FUNCTION_GAMMA28 3
|
#endif
|
||||||
#define CM_TRANSFER_FUNCTION_ST240 4
|
|
||||||
#define CM_TRANSFER_FUNCTION_EXT_LINEAR 5
|
|
||||||
#define CM_TRANSFER_FUNCTION_LOG_100 6
|
|
||||||
#define CM_TRANSFER_FUNCTION_LOG_316 7
|
|
||||||
#define CM_TRANSFER_FUNCTION_XVYCC 8
|
|
||||||
#define CM_TRANSFER_FUNCTION_SRGB 9
|
|
||||||
#define CM_TRANSFER_FUNCTION_EXT_SRGB 10
|
|
||||||
#define CM_TRANSFER_FUNCTION_ST2084_PQ 11
|
|
||||||
#define CM_TRANSFER_FUNCTION_ST428 12
|
|
||||||
#define CM_TRANSFER_FUNCTION_HLG 13
|
|
||||||
|
|
||||||
// sRGB constants
|
#if USE_TONEMAP
|
||||||
#define SRGB_POW 2.4
|
uniform float maxLuminance;
|
||||||
#define SRGB_CUT 0.0031308
|
uniform float dstMaxLuminance;
|
||||||
#define SRGB_SCALE 12.92
|
uniform float dstRefLuminance;
|
||||||
#define SRGB_ALPHA 1.055
|
#endif
|
||||||
|
|
||||||
#define BT1886_POW (1.0 / 0.45)
|
|
||||||
#define BT1886_CUT 0.018053968510807
|
|
||||||
#define BT1886_SCALE 4.5
|
|
||||||
#define BT1886_ALPHA (1.0 + 5.5 * BT1886_CUT)
|
|
||||||
|
|
||||||
// See http://car.france3.mars.free.fr/HD/INA-%2026%20jan%2006/SMPTE%20normes%20et%20confs/s240m.pdf
|
|
||||||
#define ST240_POW (1.0 / 0.45)
|
|
||||||
#define ST240_CUT 0.0228
|
|
||||||
#define ST240_SCALE 4.0
|
|
||||||
#define ST240_ALPHA 1.1115
|
|
||||||
|
|
||||||
#define ST428_POW 2.6
|
|
||||||
#define ST428_SCALE (52.37 / 48.0)
|
|
||||||
|
|
||||||
// PQ constants
|
|
||||||
#define PQ_M1 0.1593017578125
|
|
||||||
#define PQ_M2 78.84375
|
|
||||||
#define PQ_INV_M1 (1.0 / PQ_M1)
|
|
||||||
#define PQ_INV_M2 (1.0 / PQ_M2)
|
|
||||||
#define PQ_C1 0.8359375
|
|
||||||
#define PQ_C2 18.8515625
|
|
||||||
#define PQ_C3 18.6875
|
|
||||||
|
|
||||||
// HLG constants
|
|
||||||
#define HLG_D_CUT (1.0 / 12.0)
|
|
||||||
#define HLG_E_CUT 0.5
|
|
||||||
#define HLG_A 0.17883277
|
|
||||||
#define HLG_B 0.28466892
|
|
||||||
#define HLG_C 0.55991073
|
|
||||||
|
|
||||||
#define SDR_MIN_LUMINANCE 0.2
|
|
||||||
#define SDR_MAX_LUMINANCE 80.0
|
|
||||||
#define HDR_MIN_LUMINANCE 0.005
|
|
||||||
#define HDR_MAX_LUMINANCE 10000.0
|
|
||||||
#define HLG_MAX_LUMINANCE 1000.0
|
|
||||||
|
|
||||||
#define M_E 2.718281828459045
|
|
||||||
|
|
||||||
|
|
||||||
vec3 applyIcc3DLut(vec3 linearRgb01) {
|
|
||||||
vec3 x = clamp(linearRgb01, 0.0, 1.0);
|
|
||||||
|
|
||||||
// Map [0..1] to texel centers to avoid edge issues
|
|
||||||
float N = iccLutSize;
|
|
||||||
vec3 coord = (x * (N - 1.0) + 0.5) / N;
|
|
||||||
|
|
||||||
return texture(iccLut3D, coord).rgb;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 xy2xyz(vec2 xy) {
|
|
||||||
if (xy.y == 0.0)
|
|
||||||
return vec3(0.0, 0.0, 0.0);
|
|
||||||
|
|
||||||
return vec3(xy.x / xy.y, 1.0, (1.0 - xy.x - xy.y) / xy.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The primary source for these transfer functions is https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.1361-0-199802-W!!PDF-E.pdf
|
|
||||||
vec3 tfInvPQ(vec3 color) {
|
|
||||||
vec3 E = pow(clamp(color.rgb, vec3(0.0), vec3(1.0)), vec3(PQ_INV_M2));
|
|
||||||
return pow(
|
|
||||||
(max(E - PQ_C1, vec3(0.0))) / (PQ_C2 - PQ_C3 * E),
|
|
||||||
vec3(PQ_INV_M1)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 tfInvHLG(vec3 color) {
|
|
||||||
bvec3 isLow = lessThanEqual(color.rgb, vec3(HLG_E_CUT));
|
|
||||||
vec3 lo = color.rgb * color.rgb / 3.0;
|
|
||||||
vec3 hi = (exp((color.rgb - HLG_C) / HLG_A) + HLG_B) / 12.0;
|
|
||||||
return mix(hi, lo, isLow);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Many transfer functions (including sRGB) follow the same pattern: a linear
|
|
||||||
// segment for small values and a power function for larger values. The
|
|
||||||
// following function implements this pattern from which sRGB, BT.1886, and
|
|
||||||
// others can be derived by plugging in the right constants.
|
|
||||||
vec3 tfInvLinPow(vec3 color, float gamma, float thres, float scale, float alpha) {
|
|
||||||
bvec3 isLow = lessThanEqual(color.rgb, vec3(thres * scale));
|
|
||||||
vec3 lo = color.rgb / scale;
|
|
||||||
vec3 hi = pow((color.rgb + alpha - 1.0) / alpha, vec3(gamma));
|
|
||||||
return mix(hi, lo, isLow);
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 tfInvSRGB(vec3 color) {
|
|
||||||
return tfInvLinPow(color, SRGB_POW, SRGB_CUT, SRGB_SCALE, SRGB_ALPHA);
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 tfInvExtSRGB(vec3 color) {
|
|
||||||
// EXT sRGB is the sRGB transfer function mirrored around 0.
|
|
||||||
return sign(color) * tfInvSRGB(abs(color));
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 tfInvBT1886(vec3 color) {
|
|
||||||
return tfInvLinPow(color, BT1886_POW, BT1886_CUT, BT1886_SCALE, BT1886_ALPHA);
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 tfInvXVYCC(vec3 color) {
|
|
||||||
// The inverse transfer function for XVYCC is the BT1886 transfer function mirrored around 0,
|
|
||||||
// same as what EXT sRGB is to sRGB.
|
|
||||||
return sign(color) * tfInvBT1886(abs(color));
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 tfInvST240(vec3 color) {
|
|
||||||
return tfInvLinPow(color, ST240_POW, ST240_CUT, ST240_SCALE, ST240_ALPHA);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Forward transfer functions corresponding to the inverse functions above.
|
|
||||||
vec3 tfPQ(vec3 color) {
|
|
||||||
vec3 E = pow(clamp(color.rgb, vec3(0.0), vec3(1.0)), vec3(PQ_M1));
|
|
||||||
return pow(
|
|
||||||
(vec3(PQ_C1) + PQ_C2 * E) / (vec3(1.0) + PQ_C3 * E),
|
|
||||||
vec3(PQ_M2)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 tfHLG(vec3 color) {
|
|
||||||
bvec3 isLow = lessThanEqual(color.rgb, vec3(HLG_D_CUT));
|
|
||||||
vec3 lo = sqrt(max(color.rgb, vec3(0.0)) * 3.0);
|
|
||||||
vec3 hi = HLG_A * log(max(12.0 * color.rgb - HLG_B, vec3(0.0001))) + HLG_C;
|
|
||||||
return mix(hi, lo, isLow);
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 tfLinPow(vec3 color, float gamma, float thres, float scale, float alpha) {
|
|
||||||
bvec3 isLow = lessThanEqual(color.rgb, vec3(thres));
|
|
||||||
vec3 lo = color.rgb * scale;
|
|
||||||
vec3 hi = pow(color.rgb, vec3(1.0 / gamma)) * alpha - (alpha - 1.0);
|
|
||||||
return mix(hi, lo, isLow);
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 tfSRGB(vec3 color) {
|
|
||||||
return tfLinPow(color, SRGB_POW, SRGB_CUT, SRGB_SCALE, SRGB_ALPHA);
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 tfExtSRGB(vec3 color) {
|
|
||||||
// EXT sRGB is the sRGB transfer function mirrored around 0.
|
|
||||||
return sign(color) * tfSRGB(abs(color));
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 tfBT1886(vec3 color) {
|
|
||||||
return tfLinPow(color, BT1886_POW, BT1886_CUT, BT1886_SCALE, BT1886_ALPHA);
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 tfXVYCC(vec3 color) {
|
|
||||||
// The transfer function for XVYCC is the BT1886 transfer function mirrored around 0,
|
|
||||||
// same as what EXT sRGB is to sRGB.
|
|
||||||
return sign(color) * tfBT1886(abs(color));
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 tfST240(vec3 color) {
|
|
||||||
return tfLinPow(color, ST240_POW, ST240_CUT, ST240_SCALE, ST240_ALPHA);
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 toLinearRGB(vec3 color, int tf) {
|
|
||||||
switch (tf) {
|
|
||||||
case CM_TRANSFER_FUNCTION_EXT_LINEAR:
|
|
||||||
return color;
|
|
||||||
case CM_TRANSFER_FUNCTION_ST2084_PQ:
|
|
||||||
return tfInvPQ(color);
|
|
||||||
case CM_TRANSFER_FUNCTION_GAMMA22:
|
|
||||||
return pow(max(color, vec3(0.0)), vec3(2.2));
|
|
||||||
case CM_TRANSFER_FUNCTION_GAMMA28:
|
|
||||||
return pow(max(color, vec3(0.0)), vec3(2.8));
|
|
||||||
case CM_TRANSFER_FUNCTION_HLG:
|
|
||||||
return tfInvHLG(color);
|
|
||||||
case CM_TRANSFER_FUNCTION_EXT_SRGB:
|
|
||||||
return tfInvExtSRGB(color);
|
|
||||||
case CM_TRANSFER_FUNCTION_BT1886:
|
|
||||||
return tfInvBT1886(color);
|
|
||||||
case CM_TRANSFER_FUNCTION_ST240:
|
|
||||||
return tfInvST240(color);
|
|
||||||
case CM_TRANSFER_FUNCTION_LOG_100:
|
|
||||||
return mix(exp((color - 1.0) * 2.0 * log(10.0)), vec3(0.0), lessThanEqual(color, vec3(0.0)));
|
|
||||||
case CM_TRANSFER_FUNCTION_LOG_316:
|
|
||||||
return mix(exp((color - 1.0) * 2.5 * log(10.0)), vec3(0.0), lessThanEqual(color, vec3(0.0)));
|
|
||||||
case CM_TRANSFER_FUNCTION_XVYCC:
|
|
||||||
return tfInvXVYCC(color);
|
|
||||||
case CM_TRANSFER_FUNCTION_ST428:
|
|
||||||
return pow(max(color, vec3(0.0)), vec3(ST428_POW)) * ST428_SCALE;
|
|
||||||
case CM_TRANSFER_FUNCTION_SRGB:
|
|
||||||
default:
|
|
||||||
return tfInvSRGB(color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vec4 toLinear(vec4 color, int tf) {
|
|
||||||
if (tf == CM_TRANSFER_FUNCTION_EXT_LINEAR)
|
|
||||||
return color;
|
|
||||||
|
|
||||||
color.rgb /= max(color.a, 0.001);
|
|
||||||
color.rgb = toLinearRGB(color.rgb, tf);
|
|
||||||
color.rgb *= color.a;
|
|
||||||
return color;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec4 toNit(vec4 color, vec2 range) {
|
|
||||||
color.rgb = color.rgb * (range[1] - range[0]) + range[0];
|
|
||||||
return color;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 fromLinearRGB(vec3 color, int tf) {
|
|
||||||
switch (tf) {
|
|
||||||
case CM_TRANSFER_FUNCTION_EXT_LINEAR:
|
|
||||||
return color;
|
|
||||||
case CM_TRANSFER_FUNCTION_ST2084_PQ:
|
|
||||||
return tfPQ(color);
|
|
||||||
case CM_TRANSFER_FUNCTION_GAMMA22:
|
|
||||||
return pow(max(color, vec3(0.0)), vec3(1.0 / 2.2));
|
|
||||||
case CM_TRANSFER_FUNCTION_GAMMA28:
|
|
||||||
return pow(max(color, vec3(0.0)), vec3(1.0 / 2.8));
|
|
||||||
case CM_TRANSFER_FUNCTION_HLG:
|
|
||||||
return tfHLG(color);
|
|
||||||
case CM_TRANSFER_FUNCTION_EXT_SRGB:
|
|
||||||
return tfExtSRGB(color);
|
|
||||||
case CM_TRANSFER_FUNCTION_BT1886:
|
|
||||||
return tfBT1886(color);
|
|
||||||
case CM_TRANSFER_FUNCTION_ST240:
|
|
||||||
return tfST240(color);
|
|
||||||
case CM_TRANSFER_FUNCTION_LOG_100:
|
|
||||||
return mix(1.0 + log(color) / log(10.0) / 2.0, vec3(0.0), lessThanEqual(color, vec3(0.01)));
|
|
||||||
case CM_TRANSFER_FUNCTION_LOG_316:
|
|
||||||
return mix(1.0 + log(color) / log(10.0) / 2.5, vec3(0.0), lessThanEqual(color, vec3(sqrt(10.0) / 1000.0)));
|
|
||||||
case CM_TRANSFER_FUNCTION_XVYCC:
|
|
||||||
return tfXVYCC(color);
|
|
||||||
case CM_TRANSFER_FUNCTION_ST428:
|
|
||||||
return pow(max(color, vec3(0.0)) / ST428_SCALE, vec3(1.0 / ST428_POW));
|
|
||||||
case CM_TRANSFER_FUNCTION_SRGB:
|
|
||||||
default:
|
|
||||||
return tfSRGB(color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vec4 fromLinear(vec4 color, int tf) {
|
|
||||||
if (tf == CM_TRANSFER_FUNCTION_EXT_LINEAR)
|
|
||||||
return color;
|
|
||||||
|
|
||||||
color.rgb /= max(color.a, 0.001);
|
|
||||||
color.rgb = fromLinearRGB(color.rgb, tf);
|
|
||||||
color.rgb *= color.a;
|
|
||||||
return color;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec4 fromLinearNit(vec4 color, int tf, vec2 range) {
|
|
||||||
if (tf == CM_TRANSFER_FUNCTION_EXT_LINEAR)
|
|
||||||
color.rgb = color.rgb / SDR_MAX_LUMINANCE;
|
|
||||||
else {
|
|
||||||
color.rgb /= max(color.a, 0.001);
|
|
||||||
color.rgb = (color.rgb - range[0]) / (range[1] - range[0]);
|
|
||||||
color.rgb = fromLinearRGB(color.rgb, tf);
|
|
||||||
color.rgb *= color.a;
|
|
||||||
}
|
|
||||||
return color;
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "tonemap.glsl"
|
|
||||||
|
|
||||||
vec4 doColorManagement(vec4 pixColor, int srcTF, int dstTF, mat3 dstxyz) {
|
|
||||||
pixColor.rgb /= max(pixColor.a, 0.001);
|
|
||||||
pixColor.rgb = toLinearRGB(pixColor.rgb, srcTF);
|
|
||||||
|
|
||||||
if (useIcc == 1) {
|
|
||||||
pixColor.rgb = applyIcc3DLut(pixColor.rgb);
|
|
||||||
pixColor.rgb *= pixColor.a;
|
|
||||||
} else {
|
|
||||||
pixColor.rgb = convertMatrix * pixColor.rgb;
|
|
||||||
pixColor = toNit(pixColor, srcTFRange);
|
|
||||||
pixColor.rgb *= pixColor.a;
|
|
||||||
#include "do_tonemap.glsl"
|
|
||||||
pixColor = fromLinearNit(pixColor, dstTF, dstTFRange);
|
|
||||||
#include "do_sdr_mod.glsl"
|
|
||||||
}
|
|
||||||
|
|
||||||
return pixColor;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
#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 sourceTF; // eTransferFunction
|
|
||||||
uniform int targetTF; // eTransferFunction
|
|
||||||
|
|
||||||
#include "CM.glsl"
|
|
||||||
#include "gain.glsl"
|
|
||||||
|
|
||||||
layout(location = 0) out vec4 fragColor;
|
|
||||||
void main() {
|
|
||||||
vec4 pixColor = texture(tex, v_texcoord);
|
|
||||||
|
|
||||||
if (sourceTF == CM_TRANSFER_FUNCTION_ST2084_PQ) {
|
|
||||||
pixColor.rgb /= sdrBrightnessMultiplier;
|
|
||||||
}
|
|
||||||
pixColor.rgb = convertMatrix * toLinearRGB(pixColor.rgb, sourceTF);
|
|
||||||
pixColor = toNit(pixColor, vec2(srcTFRange[0], srcRefLuminance));
|
|
||||||
pixColor = fromLinearNit(pixColor, targetTF, dstTFRange);
|
|
||||||
|
|
||||||
// contrast
|
|
||||||
if (contrast != 1.0)
|
|
||||||
pixColor.rgb = gain(pixColor.rgb, contrast);
|
|
||||||
|
|
||||||
// brightness
|
|
||||||
pixColor.rgb *= max(1.0, brightness);
|
|
||||||
|
|
||||||
fragColor = pixColor;
|
|
||||||
}
|
|
||||||
|
|
@ -1,98 +0,0 @@
|
||||||
#version 300 es
|
|
||||||
#extension GL_ARB_shading_language_include : enable
|
|
||||||
|
|
||||||
precision highp float;
|
|
||||||
in vec2 v_texcoord;
|
|
||||||
|
|
||||||
uniform int sourceTF; // eTransferFunction
|
|
||||||
uniform int targetTF; // eTransferFunction
|
|
||||||
uniform mat3 targetPrimariesXYZ;
|
|
||||||
|
|
||||||
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"
|
|
||||||
#include "border.glsl"
|
|
||||||
|
|
||||||
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 don't 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];
|
|
||||||
|
|
||||||
pixColor = doColorManagement(pixColor, sourceTF, targetTF, targetPrimariesXYZ);
|
|
||||||
|
|
||||||
pixColor *= alpha * additionalAlpha;
|
|
||||||
|
|
||||||
fragColor = pixColor;
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
#version 300 es
|
#version 300 es
|
||||||
|
#define ALLOW_INCLUDES
|
||||||
|
#extension GL_ARB_shading_language_include : enable
|
||||||
|
|
||||||
precision highp float;
|
precision highp float;
|
||||||
uniform sampler2D tex;
|
uniform sampler2D tex;
|
||||||
|
|
||||||
|
|
@ -9,135 +12,10 @@ uniform float vibrancy;
|
||||||
uniform float vibrancy_darkness;
|
uniform float vibrancy_darkness;
|
||||||
|
|
||||||
in vec2 v_texcoord;
|
in vec2 v_texcoord;
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
layout(location = 0) out vec4 fragColor;
|
layout(location = 0) out vec4 fragColor;
|
||||||
|
|
||||||
|
#include "blur1.glsl"
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec2 uv = v_texcoord * 2.0;
|
fragColor = blur1(v_texcoord, tex, radius, halfpixel, passes, vibrancy, vibrancy_darkness);
|
||||||
|
|
||||||
vec4 sum = texture(tex, uv) * 4.0;
|
|
||||||
sum += texture(tex, uv - halfpixel.xy * radius);
|
|
||||||
sum += texture(tex, uv + halfpixel.xy * radius);
|
|
||||||
sum += texture(tex, uv + vec2(halfpixel.x, -halfpixel.y) * radius);
|
|
||||||
sum += texture(tex, uv - vec2(halfpixel.x, -halfpixel.y) * radius);
|
|
||||||
|
|
||||||
vec4 color = sum / 8.0;
|
|
||||||
|
|
||||||
if (vibrancy == 0.0) {
|
|
||||||
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]));
|
|
||||||
|
|
||||||
fragColor = vec4(newColor, color[3]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
130
src/render/shaders/glsl/blur1.glsl
Normal file
130
src/render/shaders/glsl/blur1.glsl
Normal file
|
|
@ -0,0 +1,130 @@
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 blur1(vec2 v_texcoord, sampler2D tex, float radius, vec2 halfpixel, int passes, float vibrancy, float vibrancy_darkness) {
|
||||||
|
vec2 uv = v_texcoord * 2.0;
|
||||||
|
|
||||||
|
vec4 sum = texture(tex, uv) * 4.0;
|
||||||
|
sum += texture(tex, uv - halfpixel.xy * radius);
|
||||||
|
sum += texture(tex, uv + halfpixel.xy * radius);
|
||||||
|
sum += texture(tex, uv + vec2(halfpixel.x, -halfpixel.y) * radius);
|
||||||
|
sum += texture(tex, uv - vec2(halfpixel.x, -halfpixel.y) * radius);
|
||||||
|
|
||||||
|
vec4 color = sum / 8.0;
|
||||||
|
|
||||||
|
if (vibrancy == 0.0) {
|
||||||
|
return 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]));
|
||||||
|
|
||||||
|
return vec4(newColor, color[3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
#version 300 es
|
#version 300 es
|
||||||
|
#define ALLOW_INCLUDES
|
||||||
|
#extension GL_ARB_shading_language_include : enable
|
||||||
|
|
||||||
precision highp float;
|
precision highp float;
|
||||||
|
|
||||||
uniform sampler2D tex;
|
uniform sampler2D tex;
|
||||||
|
|
@ -8,18 +11,8 @@ uniform vec2 halfpixel;
|
||||||
in vec2 v_texcoord;
|
in vec2 v_texcoord;
|
||||||
layout(location = 0) out vec4 fragColor;
|
layout(location = 0) out vec4 fragColor;
|
||||||
|
|
||||||
|
#include "blur2.glsl"
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec2 uv = v_texcoord / 2.0;
|
fragColor = blur2(v_texcoord, tex, radius, halfpixel);
|
||||||
|
|
||||||
vec4 sum = texture(tex, uv + vec2(-halfpixel.x * 2.0, 0.0) * radius);
|
|
||||||
|
|
||||||
sum += texture(tex, uv + vec2(-halfpixel.x, halfpixel.y) * radius) * 2.0;
|
|
||||||
sum += texture(tex, uv + vec2(0.0, halfpixel.y * 2.0) * radius);
|
|
||||||
sum += texture(tex, uv + vec2(halfpixel.x, halfpixel.y) * radius) * 2.0;
|
|
||||||
sum += texture(tex, uv + vec2(halfpixel.x * 2.0, 0.0) * radius);
|
|
||||||
sum += texture(tex, uv + vec2(halfpixel.x, -halfpixel.y) * radius) * 2.0;
|
|
||||||
sum += texture(tex, uv + vec2(0.0, -halfpixel.y * 2.0) * radius);
|
|
||||||
sum += texture(tex, uv + vec2(-halfpixel.x, -halfpixel.y) * radius) * 2.0;
|
|
||||||
|
|
||||||
fragColor = sum / 12.0;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
15
src/render/shaders/glsl/blur2.glsl
Normal file
15
src/render/shaders/glsl/blur2.glsl
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
vec4 blur2(vec2 v_texcoord, sampler2D tex, float radius, vec2 halfpixel) {
|
||||||
|
vec2 uv = v_texcoord / 2.0;
|
||||||
|
|
||||||
|
vec4 sum = texture(tex, uv + vec2(-halfpixel.x * 2.0, 0.0) * radius);
|
||||||
|
|
||||||
|
sum += texture(tex, uv + vec2(-halfpixel.x, halfpixel.y) * radius) * 2.0;
|
||||||
|
sum += texture(tex, uv + vec2(0.0, halfpixel.y * 2.0) * radius);
|
||||||
|
sum += texture(tex, uv + vec2(halfpixel.x, halfpixel.y) * radius) * 2.0;
|
||||||
|
sum += texture(tex, uv + vec2(halfpixel.x * 2.0, 0.0) * radius);
|
||||||
|
sum += texture(tex, uv + vec2(halfpixel.x, -halfpixel.y) * radius) * 2.0;
|
||||||
|
sum += texture(tex, uv + vec2(0.0, -halfpixel.y * 2.0) * radius);
|
||||||
|
sum += texture(tex, uv + vec2(-halfpixel.x, -halfpixel.y) * radius) * 2.0;
|
||||||
|
|
||||||
|
return sum / 12.0;
|
||||||
|
}
|
||||||
17
src/render/shaders/glsl/blurFinish.glsl
Normal file
17
src/render/shaders/glsl/blurFinish.glsl
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 blurFinish(vec4 pixColor, vec2 v_texcoord, float noise, float brightness) {
|
||||||
|
// noise
|
||||||
|
float noiseHash = hash(v_texcoord);
|
||||||
|
float noiseAmount = noiseHash - 0.5;
|
||||||
|
pixColor.rgb += noiseAmount * noise;
|
||||||
|
|
||||||
|
// brightness
|
||||||
|
pixColor.rgb *= min(1.0, brightness);
|
||||||
|
|
||||||
|
return pixColor;
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#version 300 es
|
#version 300 es
|
||||||
|
#define ALLOW_INCLUDES
|
||||||
#extension GL_ARB_shading_language_include : enable
|
#extension GL_ARB_shading_language_include : enable
|
||||||
|
|
||||||
precision highp float;
|
precision highp float;
|
||||||
|
|
@ -8,23 +9,11 @@ uniform sampler2D tex;
|
||||||
uniform float noise;
|
uniform float noise;
|
||||||
uniform float brightness;
|
uniform float brightness;
|
||||||
|
|
||||||
float hash(vec2 p) {
|
#include "blurFinish.glsl"
|
||||||
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;
|
layout(location = 0) out vec4 fragColor;
|
||||||
void main() {
|
void main() {
|
||||||
vec4 pixColor = texture(tex, v_texcoord);
|
vec4 pixColor = texture(tex, v_texcoord);
|
||||||
|
|
||||||
// noise
|
fragColor = blurFinish(pixColor, v_texcoord, noise, brightness);
|
||||||
float noiseHash = hash(v_texcoord);
|
|
||||||
float noiseAmount = noiseHash - 0.5;
|
|
||||||
pixColor.rgb += noiseAmount * noise;
|
|
||||||
|
|
||||||
// brightness
|
|
||||||
pixColor.rgb *= min(1.0, brightness);
|
|
||||||
|
|
||||||
fragColor = pixColor;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
#version 300 es
|
#version 300 es
|
||||||
|
#define ALLOW_INCLUDES
|
||||||
#extension GL_ARB_shading_language_include : enable
|
#extension GL_ARB_shading_language_include : enable
|
||||||
|
|
||||||
|
#include "defines.h"
|
||||||
|
|
||||||
precision highp float;
|
precision highp float;
|
||||||
in vec2 v_texcoord; // is in 0-1
|
in vec2 v_texcoord; // is in 0-1
|
||||||
uniform sampler2D tex;
|
uniform sampler2D tex;
|
||||||
|
|
@ -8,19 +11,28 @@ uniform sampler2D tex;
|
||||||
uniform float contrast;
|
uniform float contrast;
|
||||||
uniform float brightness;
|
uniform float brightness;
|
||||||
|
|
||||||
#include "CM.glsl"
|
uniform int sourceTF; // eTransferFunction
|
||||||
#include "gain.glsl"
|
uniform int targetTF; // eTransferFunction
|
||||||
|
|
||||||
|
#if USE_CM
|
||||||
|
uniform vec2 srcTFRange;
|
||||||
|
uniform vec2 dstTFRange;
|
||||||
|
|
||||||
|
uniform float srcRefLuminance;
|
||||||
|
uniform mat3 convertMatrix;
|
||||||
|
|
||||||
|
uniform float sdrBrightnessMultiplier;
|
||||||
|
#include "cm_helpers.glsl"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "blurprepare.glsl"
|
||||||
|
|
||||||
layout(location = 0) out vec4 fragColor;
|
layout(location = 0) out vec4 fragColor;
|
||||||
void main() {
|
void main() {
|
||||||
vec4 pixColor = texture(tex, v_texcoord);
|
fragColor = fragColor = blurPrepare(texture(tex, v_texcoord), contrast, brightness
|
||||||
|
#if USE_CM
|
||||||
// contrast
|
,
|
||||||
if (contrast != 1.0)
|
sourceTF, targetTF, convertMatrix, srcTFRange, dstTFRange, srcRefLuminance, sdrBrightnessMultiplier
|
||||||
pixColor.rgb = gain(pixColor.rgb, contrast);
|
#endif
|
||||||
|
);
|
||||||
// brightness
|
|
||||||
pixColor.rgb *= max(1.0, brightness);
|
|
||||||
|
|
||||||
fragColor = pixColor;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
37
src/render/shaders/glsl/blurprepare.glsl
Normal file
37
src/render/shaders/glsl/blurprepare.glsl
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
#ifndef ALLOW_INCLUDES
|
||||||
|
#define ALLOW_INCLUDES
|
||||||
|
#extension GL_ARB_shading_language_include : enable
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "defines.h"
|
||||||
|
|
||||||
|
#if USE_CM
|
||||||
|
#include "cm_helpers.glsl"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "gain.glsl"
|
||||||
|
|
||||||
|
vec4 blurPrepare(vec4 pixColor, float contrast, float brightness
|
||||||
|
#if USE_CM
|
||||||
|
,
|
||||||
|
int sourceTF, int targetTF, mat3 convertMatrix, vec2 srcTFRange, vec2 dstTFRange, float srcRefLuminance, float sdrBrightnessMultiplier
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
|
#if USE_CM
|
||||||
|
if (sourceTF == CM_TRANSFER_FUNCTION_ST2084_PQ) {
|
||||||
|
pixColor.rgb /= sdrBrightnessMultiplier;
|
||||||
|
}
|
||||||
|
pixColor.rgb = convertMatrix * toLinearRGB(pixColor.rgb, sourceTF);
|
||||||
|
pixColor = toNit(pixColor, vec2(srcTFRange[0], srcRefLuminance));
|
||||||
|
pixColor = fromLinearNit(pixColor, targetTF, dstTFRange);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// contrast
|
||||||
|
if (contrast != 1.0)
|
||||||
|
pixColor.rgb = gain(pixColor.rgb, contrast);
|
||||||
|
|
||||||
|
// brightness
|
||||||
|
pixColor.rgb *= max(1.0, brightness);
|
||||||
|
|
||||||
|
return pixColor;
|
||||||
|
}
|
||||||
|
|
@ -1,9 +1,14 @@
|
||||||
#version 300 es
|
#version 300 es
|
||||||
|
#define ALLOW_INCLUDES
|
||||||
#extension GL_ARB_shading_language_include : enable
|
#extension GL_ARB_shading_language_include : enable
|
||||||
|
|
||||||
precision highp float;
|
precision highp float;
|
||||||
in vec2 v_texcoord;
|
in vec2 v_texcoord;
|
||||||
|
|
||||||
|
uniform int sourceTF; // eTransferFunction
|
||||||
|
uniform int targetTF; // eTransferFunction
|
||||||
|
uniform mat3 targetPrimariesXYZ;
|
||||||
|
|
||||||
uniform vec2 fullSizeUntransformed;
|
uniform vec2 fullSizeUntransformed;
|
||||||
uniform float radiusOuter;
|
uniform float radiusOuter;
|
||||||
uniform float thick;
|
uniform float thick;
|
||||||
|
|
@ -18,75 +23,38 @@ uniform float angle2;
|
||||||
uniform float gradientLerp;
|
uniform float gradientLerp;
|
||||||
uniform float alpha;
|
uniform float alpha;
|
||||||
|
|
||||||
|
uniform float radius;
|
||||||
|
uniform float roundingPower;
|
||||||
|
uniform vec2 topLeft;
|
||||||
|
uniform vec2 fullSize;
|
||||||
#include "rounding.glsl"
|
#include "rounding.glsl"
|
||||||
#include "CM.glsl"
|
#include "CM.glsl"
|
||||||
#include "border.glsl"
|
#include "border.glsl"
|
||||||
|
|
||||||
layout(location = 0) out vec4 fragColor;
|
layout(location = 0) out vec4 fragColor;
|
||||||
void main() {
|
void main() {
|
||||||
highp vec2 pixCoord = vec2(gl_FragCoord);
|
fragColor = getBorder(v_texcoord, alpha, fullSizeUntransformed, radiusOuter, thick, radius, roundingPower, topLeft, fullSize, gradientLength, gradient, angle, gradient2Length,
|
||||||
highp vec2 pixCoordOuter = pixCoord;
|
gradient2, angle2, gradientLerp
|
||||||
highp vec2 originalPixCoord = v_texcoord;
|
#if USE_CM
|
||||||
originalPixCoord *= fullSizeUntransformed;
|
,
|
||||||
float additionalAlpha = 1.0;
|
sourceTF, targetTF, convertMatrix, srcTFRange, dstTFRange
|
||||||
|
#if USE_ICC
|
||||||
vec4 pixColor = vec4(1.0, 1.0, 1.0, 1.0);
|
,
|
||||||
|
iccLut3D, iccLutSize
|
||||||
bool done = false;
|
#else
|
||||||
|
#if USE_TONEMAP || USE_SDR_MOD
|
||||||
pixCoord -= topLeft + fullSize * 0.5;
|
,
|
||||||
pixCoord *= vec2(lessThan(pixCoord, vec2(0.0))) * -2.0 + 1.0;
|
targetPrimariesXYZ
|
||||||
pixCoordOuter = pixCoord;
|
#endif
|
||||||
pixCoord -= fullSize * 0.5 - radius;
|
#if USE_TONEMAP
|
||||||
pixCoordOuter -= fullSize * 0.5 - radiusOuter;
|
,
|
||||||
|
maxLuminance, dstMaxLuminance, dstRefLuminance, srcRefLuminance
|
||||||
// center the pixes don't make it top-left
|
#endif
|
||||||
pixCoord += vec2(1.0, 1.0) / fullSize;
|
#if USE_SDR_MOD
|
||||||
pixCoordOuter += vec2(1.0, 1.0) / fullSize;
|
,
|
||||||
|
sdrSaturation, sdrBrightnessMultiplier
|
||||||
if (min(pixCoord.x, pixCoord.y) > 0.0 && radius > 0.0) {
|
#endif
|
||||||
float dist = pow(pow(pixCoord.x,roundingPower)+pow(pixCoord.y,roundingPower),1.0/roundingPower);
|
#endif
|
||||||
float distOuter = pow(pow(pixCoordOuter.x,roundingPower)+pow(pixCoordOuter.y,roundingPower),1.0/roundingPower);
|
#endif
|
||||||
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];
|
|
||||||
|
|
||||||
pixColor *= alpha * additionalAlpha;
|
|
||||||
|
|
||||||
fragColor = pixColor;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,24 @@
|
||||||
|
#ifndef ALLOW_INCLUDES
|
||||||
|
#define ALLOW_INCLUDES
|
||||||
|
#extension GL_ARB_shading_language_include : enable
|
||||||
|
#endif
|
||||||
|
#include "cm_helpers.glsl"
|
||||||
|
#if USE_ROUNDING
|
||||||
|
#include "rounding.glsl"
|
||||||
|
#endif
|
||||||
|
|
||||||
vec4 okLabAToSrgb(vec4 lab) {
|
vec4 okLabAToSrgb(vec4 lab) {
|
||||||
float l = pow(lab[0] + lab[1] * 0.3963377774 + lab[2] * 0.2158037573, 3.0);
|
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 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);
|
float s = pow(lab[0] + lab[1] * (-0.0894841775) + lab[2] * (-1.2914855480), 3.0);
|
||||||
|
|
||||||
return vec4(fromLinearRGB(
|
return vec4(fromLinearRGB(vec3(l * 4.0767416621 + m * -3.3077115913 + s * 0.2309699292, l * (-1.2684380046) + m * 2.6097574011 + s * (-0.3413193965),
|
||||||
vec3(
|
l * (-0.0041960863) + m * (-0.7034186147) + s * 1.7076147010),
|
||||||
l * 4.0767416621 + m * -3.3077115913 + s * 0.2309699292,
|
CM_TRANSFER_FUNCTION_GAMMA22),
|
||||||
l * (-1.2684380046) + m * 2.6097574011 + s * (-0.3413193965),
|
lab[3]);
|
||||||
l * (-0.0041960863) + m * (-0.7034186147) + s * 1.7076147010
|
|
||||||
), CM_TRANSFER_FUNCTION_GAMMA22
|
|
||||||
), lab[3]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
vec4 getOkColorForCoordArray1(vec2 normalizedCoord) {
|
vec4 getOkColorForCoordArray1(vec2 normalizedCoord, int gradientLength, vec4 gradient[10], float angle) {
|
||||||
if (gradientLength < 2)
|
if (gradientLength < 2)
|
||||||
return gradient[0];
|
return gradient[0];
|
||||||
|
|
||||||
|
|
@ -41,7 +47,7 @@ vec4 getOkColorForCoordArray1(vec2 normalizedCoord) {
|
||||||
return gradient[top] * (progress - float(bottom)) + gradient[bottom] * (float(top) - progress);
|
return gradient[top] * (progress - float(bottom)) + gradient[bottom] * (float(top) - progress);
|
||||||
}
|
}
|
||||||
|
|
||||||
vec4 getOkColorForCoordArray2(vec2 normalizedCoord) {
|
vec4 getOkColorForCoordArray2(vec2 normalizedCoord, float angle, int gradient2Length, vec4 gradient2[10], float angle2) {
|
||||||
if (gradient2Length < 2)
|
if (gradient2Length < 2)
|
||||||
return gradient2[0];
|
return gradient2[0];
|
||||||
|
|
||||||
|
|
@ -70,13 +76,128 @@ vec4 getOkColorForCoordArray2(vec2 normalizedCoord) {
|
||||||
return gradient2[top] * (progress - float(bottom)) + gradient2[bottom] * (float(top) - progress);
|
return gradient2[top] * (progress - float(bottom)) + gradient2[bottom] * (float(top) - progress);
|
||||||
}
|
}
|
||||||
|
|
||||||
vec4 getColorForCoord(vec2 normalizedCoord) {
|
vec4 getColorForCoord(vec2 normalizedCoord, int gradientLength, vec4 gradient[10], float angle, int gradient2Length, vec4 gradient2[10], float angle2, float gradientLerp) {
|
||||||
vec4 result1 = getOkColorForCoordArray1(normalizedCoord);
|
vec4 result1 = getOkColorForCoordArray1(normalizedCoord, gradientLength, gradient, angle);
|
||||||
|
|
||||||
if (gradient2Length <= 0)
|
if (gradient2Length <= 0)
|
||||||
return okLabAToSrgb(result1);
|
return okLabAToSrgb(result1);
|
||||||
|
|
||||||
vec4 result2 = getOkColorForCoordArray2(normalizedCoord);
|
vec4 result2 = getOkColorForCoordArray2(normalizedCoord, angle, gradient2Length, gradient2, angle2);
|
||||||
|
|
||||||
return okLabAToSrgb(mix(result1, result2, gradientLerp));
|
return okLabAToSrgb(mix(result1, result2, gradientLerp));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vec4 getBorder(vec2 v_texcoord, float alpha, vec2 fullSizeUntransformed, float radiusOuter, float thick, float radius, float roundingPower, vec2 topLeft, vec2 fullSize,
|
||||||
|
int gradientLength, vec4 gradient[10], float angle, int gradient2Length, vec4 gradient2[10], float angle2, float gradientLerp
|
||||||
|
#if USE_CM
|
||||||
|
,
|
||||||
|
int sourceTF, int targetTF, mat3 convertMatrix, vec2 srcTFRange, vec2 dstTFRange
|
||||||
|
#if USE_ICC
|
||||||
|
,
|
||||||
|
highp sampler3D iccLut3D, float iccLutSize
|
||||||
|
#else
|
||||||
|
#if USE_TONEMAP || USE_SDR_MOD
|
||||||
|
,
|
||||||
|
mat3 targetPrimariesXYZ
|
||||||
|
#endif
|
||||||
|
#if USE_TONEMAP
|
||||||
|
,
|
||||||
|
float maxLuminance, float dstMaxLuminance, float dstRefLuminance, float srcRefLuminance
|
||||||
|
#endif
|
||||||
|
#if USE_SDR_MOD
|
||||||
|
,
|
||||||
|
float sdrSaturation, float sdrBrightnessMultiplier
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
|
vec2 pixCoord = vec2(gl_FragCoord);
|
||||||
|
vec2 pixCoordOuter = pixCoord;
|
||||||
|
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 don't make it top-left
|
||||||
|
pixCoord += vec2(1.0, 1.0) / fullSize;
|
||||||
|
pixCoordOuter += vec2(1.0, 1.0) / fullSize;
|
||||||
|
|
||||||
|
#if USE_ROUNDING
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// 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, gradientLength, gradient, angle, gradient2Length, gradient2, angle2, gradientLerp);
|
||||||
|
pixColor.rgb *= pixColor[3];
|
||||||
|
|
||||||
|
#if USE_CM
|
||||||
|
pixColor = doColorManagement(pixColor, sourceTF, targetTF, convertMatrix, srcTFRange, dstTFRange
|
||||||
|
#if USE_ICC
|
||||||
|
,
|
||||||
|
iccLut3D, iccLutSize
|
||||||
|
#else
|
||||||
|
#if USE_TONEMAP || USE_SDR_MOD
|
||||||
|
,
|
||||||
|
targetPrimariesXYZ
|
||||||
|
#endif
|
||||||
|
#if USE_TONEMAP
|
||||||
|
,
|
||||||
|
maxLuminance, dstMaxLuminance, dstRefLuminance, srcRefLuminance
|
||||||
|
#endif
|
||||||
|
#if USE_SDR_MOD
|
||||||
|
,
|
||||||
|
sdrSaturation, sdrBrightnessMultiplier
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
pixColor *= alpha * additionalAlpha;
|
||||||
|
|
||||||
|
return pixColor;
|
||||||
|
}
|
||||||
|
|
|
||||||
248
src/render/shaders/glsl/cm_helpers.glsl
Normal file
248
src/render/shaders/glsl/cm_helpers.glsl
Normal file
|
|
@ -0,0 +1,248 @@
|
||||||
|
#ifndef ALLOW_INCLUDES
|
||||||
|
#define ALLOW_INCLUDES
|
||||||
|
#extension GL_ARB_shading_language_include : enable
|
||||||
|
#endif
|
||||||
|
#ifndef CM_HELPERS_GLSL
|
||||||
|
#define CM_HELPERS_GLSL
|
||||||
|
|
||||||
|
#include "defines.h"
|
||||||
|
#include "constants.h"
|
||||||
|
|
||||||
|
#if USE_SDR_MOD
|
||||||
|
vec4 saturate(vec4 color, mat3 primaries, float saturation) {
|
||||||
|
if (saturation == 1.0)
|
||||||
|
return color;
|
||||||
|
vec3 brightness = vec3(primaries[1][0], primaries[1][1], primaries[1][2]);
|
||||||
|
float Y = dot(color.rgb, brightness);
|
||||||
|
return vec4(mix(vec3(Y), color.rgb, saturation), color[3]);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
vec3 applyIcc3DLut(vec3 linearRgb01, highp sampler3D iccLut3D, float iccLutSize) {
|
||||||
|
vec3 x = clamp(linearRgb01, 0.0, 1.0);
|
||||||
|
|
||||||
|
// Map [0..1] to texel centers to avoid edge issues
|
||||||
|
float N = iccLutSize;
|
||||||
|
vec3 coord = (x * (N - 1.0) + 0.5) / N;
|
||||||
|
|
||||||
|
return texture(iccLut3D, coord).rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 xy2xyz(vec2 xy) {
|
||||||
|
if (xy.y == 0.0)
|
||||||
|
return vec3(0.0, 0.0, 0.0);
|
||||||
|
|
||||||
|
return vec3(xy.x / xy.y, 1.0, (1.0 - xy.x - xy.y) / xy.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The primary source for these transfer functions is https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.1361-0-199802-W!!PDF-E.pdf
|
||||||
|
vec3 tfInvPQ(vec3 color) {
|
||||||
|
vec3 E = pow(clamp(color.rgb, vec3(0.0), vec3(1.0)), vec3(PQ_INV_M2));
|
||||||
|
return pow((max(E - PQ_C1, vec3(0.0))) / (PQ_C2 - PQ_C3 * E), vec3(PQ_INV_M1));
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 tfInvHLG(vec3 color) {
|
||||||
|
bvec3 isLow = lessThanEqual(color.rgb, vec3(HLG_E_CUT));
|
||||||
|
vec3 lo = color.rgb * color.rgb / 3.0;
|
||||||
|
vec3 hi = (exp((color.rgb - HLG_C) / HLG_A) + HLG_B) / 12.0;
|
||||||
|
return mix(hi, lo, isLow);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Many transfer functions (including sRGB) follow the same pattern: a linear
|
||||||
|
// segment for small values and a power function for larger values. The
|
||||||
|
// following function implements this pattern from which sRGB, BT.1886, and
|
||||||
|
// others can be derived by plugging in the right constants.
|
||||||
|
vec3 tfInvLinPow(vec3 color, float gamma, float thres, float scale, float alpha) {
|
||||||
|
bvec3 isLow = lessThanEqual(color.rgb, vec3(thres * scale));
|
||||||
|
vec3 lo = color.rgb / scale;
|
||||||
|
vec3 hi = pow((color.rgb + alpha - 1.0) / alpha, vec3(gamma));
|
||||||
|
return mix(hi, lo, isLow);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 tfInvSRGB(vec3 color) {
|
||||||
|
return tfInvLinPow(color, SRGB_POW, SRGB_CUT, SRGB_SCALE, SRGB_ALPHA);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 tfInvExtSRGB(vec3 color) {
|
||||||
|
// EXT sRGB is the sRGB transfer function mirrored around 0.
|
||||||
|
return sign(color) * tfInvSRGB(abs(color));
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 tfInvBT1886(vec3 color) {
|
||||||
|
return tfInvLinPow(color, BT1886_POW, BT1886_CUT, BT1886_SCALE, BT1886_ALPHA);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 tfInvXVYCC(vec3 color) {
|
||||||
|
// The inverse transfer function for XVYCC is the BT1886 transfer function mirrored around 0,
|
||||||
|
// same as what EXT sRGB is to sRGB.
|
||||||
|
return sign(color) * tfInvBT1886(abs(color));
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 tfInvST240(vec3 color) {
|
||||||
|
return tfInvLinPow(color, ST240_POW, ST240_CUT, ST240_SCALE, ST240_ALPHA);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forward transfer functions corresponding to the inverse functions above.
|
||||||
|
vec3 tfPQ(vec3 color) {
|
||||||
|
vec3 E = pow(clamp(color.rgb, vec3(0.0), vec3(1.0)), vec3(PQ_M1));
|
||||||
|
return pow((vec3(PQ_C1) + PQ_C2 * E) / (vec3(1.0) + PQ_C3 * E), vec3(PQ_M2));
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 tfHLG(vec3 color) {
|
||||||
|
bvec3 isLow = lessThanEqual(color.rgb, vec3(HLG_D_CUT));
|
||||||
|
vec3 lo = sqrt(max(color.rgb, vec3(0.0)) * 3.0);
|
||||||
|
vec3 hi = HLG_A * log(max(12.0 * color.rgb - HLG_B, vec3(0.0001))) + HLG_C;
|
||||||
|
return mix(hi, lo, isLow);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 tfLinPow(vec3 color, float gamma, float thres, float scale, float alpha) {
|
||||||
|
bvec3 isLow = lessThanEqual(color.rgb, vec3(thres));
|
||||||
|
vec3 lo = color.rgb * scale;
|
||||||
|
vec3 hi = pow(color.rgb, vec3(1.0 / gamma)) * alpha - (alpha - 1.0);
|
||||||
|
return mix(hi, lo, isLow);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 tfSRGB(vec3 color) {
|
||||||
|
return tfLinPow(color, SRGB_POW, SRGB_CUT, SRGB_SCALE, SRGB_ALPHA);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 tfExtSRGB(vec3 color) {
|
||||||
|
// EXT sRGB is the sRGB transfer function mirrored around 0.
|
||||||
|
return sign(color) * tfSRGB(abs(color));
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 tfBT1886(vec3 color) {
|
||||||
|
return tfLinPow(color, BT1886_POW, BT1886_CUT, BT1886_SCALE, BT1886_ALPHA);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 tfXVYCC(vec3 color) {
|
||||||
|
// The transfer function for XVYCC is the BT1886 transfer function mirrored around 0,
|
||||||
|
// same as what EXT sRGB is to sRGB.
|
||||||
|
return sign(color) * tfBT1886(abs(color));
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 tfST240(vec3 color) {
|
||||||
|
return tfLinPow(color, ST240_POW, ST240_CUT, ST240_SCALE, ST240_ALPHA);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 toLinearRGB(vec3 color, int tf) {
|
||||||
|
switch (tf) {
|
||||||
|
case CM_TRANSFER_FUNCTION_EXT_LINEAR: return color;
|
||||||
|
case CM_TRANSFER_FUNCTION_ST2084_PQ: return tfInvPQ(color);
|
||||||
|
case CM_TRANSFER_FUNCTION_GAMMA22: return pow(max(color, vec3(0.0)), vec3(2.2));
|
||||||
|
case CM_TRANSFER_FUNCTION_GAMMA28: return pow(max(color, vec3(0.0)), vec3(2.8));
|
||||||
|
case CM_TRANSFER_FUNCTION_HLG: return tfInvHLG(color);
|
||||||
|
case CM_TRANSFER_FUNCTION_EXT_SRGB: return tfInvExtSRGB(color);
|
||||||
|
case CM_TRANSFER_FUNCTION_BT1886: return tfInvBT1886(color);
|
||||||
|
case CM_TRANSFER_FUNCTION_ST240: return tfInvST240(color);
|
||||||
|
case CM_TRANSFER_FUNCTION_LOG_100: return mix(exp((color - 1.0) * 2.0 * log(10.0)), vec3(0.0), lessThanEqual(color, vec3(0.0)));
|
||||||
|
case CM_TRANSFER_FUNCTION_LOG_316: return mix(exp((color - 1.0) * 2.5 * log(10.0)), vec3(0.0), lessThanEqual(color, vec3(0.0)));
|
||||||
|
case CM_TRANSFER_FUNCTION_XVYCC: return tfInvXVYCC(color);
|
||||||
|
case CM_TRANSFER_FUNCTION_ST428: return pow(max(color, vec3(0.0)), vec3(ST428_POW)) * ST428_SCALE;
|
||||||
|
case CM_TRANSFER_FUNCTION_SRGB:
|
||||||
|
default: return tfInvSRGB(color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 toLinear(vec4 color, int tf) {
|
||||||
|
if (tf == CM_TRANSFER_FUNCTION_EXT_LINEAR)
|
||||||
|
return color;
|
||||||
|
|
||||||
|
color.rgb /= max(color.a, 0.001);
|
||||||
|
color.rgb = toLinearRGB(color.rgb, tf);
|
||||||
|
color.rgb *= color.a;
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 toNit(vec4 color, vec2 range) {
|
||||||
|
color.rgb = color.rgb * (range[1] - range[0]) + range[0];
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 fromLinearRGB(vec3 color, int tf) {
|
||||||
|
switch (tf) {
|
||||||
|
case CM_TRANSFER_FUNCTION_EXT_LINEAR: return color;
|
||||||
|
case CM_TRANSFER_FUNCTION_ST2084_PQ: return tfPQ(color);
|
||||||
|
case CM_TRANSFER_FUNCTION_GAMMA22: return pow(max(color, vec3(0.0)), vec3(1.0 / 2.2));
|
||||||
|
case CM_TRANSFER_FUNCTION_GAMMA28: return pow(max(color, vec3(0.0)), vec3(1.0 / 2.8));
|
||||||
|
case CM_TRANSFER_FUNCTION_HLG: return tfHLG(color);
|
||||||
|
case CM_TRANSFER_FUNCTION_EXT_SRGB: return tfExtSRGB(color);
|
||||||
|
case CM_TRANSFER_FUNCTION_BT1886: return tfBT1886(color);
|
||||||
|
case CM_TRANSFER_FUNCTION_ST240: return tfST240(color);
|
||||||
|
case CM_TRANSFER_FUNCTION_LOG_100: return mix(1.0 + log(color) / log(10.0) / 2.0, vec3(0.0), lessThanEqual(color, vec3(0.01)));
|
||||||
|
case CM_TRANSFER_FUNCTION_LOG_316: return mix(1.0 + log(color) / log(10.0) / 2.5, vec3(0.0), lessThanEqual(color, vec3(sqrt(10.0) / 1000.0)));
|
||||||
|
case CM_TRANSFER_FUNCTION_XVYCC: return tfXVYCC(color);
|
||||||
|
case CM_TRANSFER_FUNCTION_ST428: return pow(max(color, vec3(0.0)) / ST428_SCALE, vec3(1.0 / ST428_POW));
|
||||||
|
case CM_TRANSFER_FUNCTION_SRGB:
|
||||||
|
default: return tfSRGB(color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 fromLinear(vec4 color, int tf) {
|
||||||
|
if (tf == CM_TRANSFER_FUNCTION_EXT_LINEAR)
|
||||||
|
return color;
|
||||||
|
|
||||||
|
color.rgb /= max(color.a, 0.001);
|
||||||
|
color.rgb = fromLinearRGB(color.rgb, tf);
|
||||||
|
color.rgb *= color.a;
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 fromLinearNit(vec4 color, int tf, vec2 range) {
|
||||||
|
if (tf == CM_TRANSFER_FUNCTION_EXT_LINEAR)
|
||||||
|
color.rgb = color.rgb / SDR_MAX_LUMINANCE;
|
||||||
|
else {
|
||||||
|
color.rgb /= max(color.a, 0.001);
|
||||||
|
color.rgb = (color.rgb - range[0]) / (range[1] - range[0]);
|
||||||
|
color.rgb = fromLinearRGB(color.rgb, tf);
|
||||||
|
color.rgb *= color.a;
|
||||||
|
}
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if USE_TONEMAP
|
||||||
|
#include "tonemap.glsl"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
vec4 doColorManagement(vec4 pixColor, int srcTF, int dstTF, mat3 convertMatrix, vec2 srcTFRange, vec2 dstTFRange
|
||||||
|
#if USE_ICC
|
||||||
|
,
|
||||||
|
highp sampler3D iccLut3D, float iccLutSize
|
||||||
|
#else
|
||||||
|
#if USE_TONEMAP || USE_SDR_MOD
|
||||||
|
,
|
||||||
|
mat3 dstxyz
|
||||||
|
#endif
|
||||||
|
#if USE_TONEMAP
|
||||||
|
,
|
||||||
|
float maxLuminance, float dstMaxLuminance, float dstRefLuminance, float srcRefLuminance
|
||||||
|
#endif
|
||||||
|
#if USE_SDR_MOD
|
||||||
|
,
|
||||||
|
float sdrSaturation, float sdrBrightnessMultiplier
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
|
pixColor.rgb /= max(pixColor.a, 0.001);
|
||||||
|
pixColor.rgb = toLinearRGB(pixColor.rgb, srcTF);
|
||||||
|
#if USE_ICC
|
||||||
|
pixColor.rgb = applyIcc3DLut(pixColor.rgb, iccLut3D, iccLutSize);
|
||||||
|
pixColor.rgb *= pixColor.a;
|
||||||
|
#else
|
||||||
|
pixColor.rgb = convertMatrix * pixColor.rgb;
|
||||||
|
pixColor = toNit(pixColor, srcTFRange);
|
||||||
|
pixColor.rgb *= pixColor.a;
|
||||||
|
#if USE_TONEMAP
|
||||||
|
pixColor = tonemap(pixColor, dstxyz, maxLuminance, dstMaxLuminance, dstRefLuminance, srcRefLuminance);
|
||||||
|
#endif
|
||||||
|
pixColor = fromLinearNit(pixColor, dstTF, dstTFRange);
|
||||||
|
#if USE_SDR_MOD
|
||||||
|
pixColor = saturate(pixColor, dstxyz, sdrSaturation);
|
||||||
|
pixColor.rgb *= sdrBrightnessMultiplier;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return pixColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
62
src/render/shaders/glsl/constants.h
Normal file
62
src/render/shaders/glsl/constants.h
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
#ifndef CONSTANTS_H
|
||||||
|
#define CONSTANTS_H
|
||||||
|
//enum eTransferFunction
|
||||||
|
#define CM_TRANSFER_FUNCTION_BT1886 1
|
||||||
|
#define CM_TRANSFER_FUNCTION_GAMMA22 2
|
||||||
|
#define CM_TRANSFER_FUNCTION_GAMMA28 3
|
||||||
|
#define CM_TRANSFER_FUNCTION_ST240 4
|
||||||
|
#define CM_TRANSFER_FUNCTION_EXT_LINEAR 5
|
||||||
|
#define CM_TRANSFER_FUNCTION_LOG_100 6
|
||||||
|
#define CM_TRANSFER_FUNCTION_LOG_316 7
|
||||||
|
#define CM_TRANSFER_FUNCTION_XVYCC 8
|
||||||
|
#define CM_TRANSFER_FUNCTION_SRGB 9
|
||||||
|
#define CM_TRANSFER_FUNCTION_EXT_SRGB 10
|
||||||
|
#define CM_TRANSFER_FUNCTION_ST2084_PQ 11
|
||||||
|
#define CM_TRANSFER_FUNCTION_ST428 12
|
||||||
|
#define CM_TRANSFER_FUNCTION_HLG 13
|
||||||
|
|
||||||
|
// sRGB constants
|
||||||
|
#define SRGB_POW 2.4
|
||||||
|
#define SRGB_CUT 0.0031308
|
||||||
|
#define SRGB_SCALE 12.92
|
||||||
|
#define SRGB_ALPHA 1.055
|
||||||
|
|
||||||
|
#define BT1886_POW (1.0 / 0.45)
|
||||||
|
#define BT1886_CUT 0.018053968510807
|
||||||
|
#define BT1886_SCALE 4.5
|
||||||
|
#define BT1886_ALPHA (1.0 + 5.5 * BT1886_CUT)
|
||||||
|
|
||||||
|
// See http://car.france3.mars.free.fr/HD/INA-%2026%20jan%2006/SMPTE%20normes%20et%20confs/s240m.pdf
|
||||||
|
#define ST240_POW (1.0 / 0.45)
|
||||||
|
#define ST240_CUT 0.0228
|
||||||
|
#define ST240_SCALE 4.0
|
||||||
|
#define ST240_ALPHA 1.1115
|
||||||
|
|
||||||
|
#define ST428_POW 2.6
|
||||||
|
#define ST428_SCALE (52.37 / 48.0)
|
||||||
|
|
||||||
|
// PQ constants
|
||||||
|
#define PQ_M1 0.1593017578125
|
||||||
|
#define PQ_M2 78.84375
|
||||||
|
#define PQ_INV_M1 (1.0 / PQ_M1)
|
||||||
|
#define PQ_INV_M2 (1.0 / PQ_M2)
|
||||||
|
#define PQ_C1 0.8359375
|
||||||
|
#define PQ_C2 18.8515625
|
||||||
|
#define PQ_C3 18.6875
|
||||||
|
|
||||||
|
// HLG constants
|
||||||
|
#define HLG_D_CUT (1.0 / 12.0)
|
||||||
|
#define HLG_E_CUT 0.5
|
||||||
|
#define HLG_A 0.17883277
|
||||||
|
#define HLG_B 0.28466892
|
||||||
|
#define HLG_C 0.55991073
|
||||||
|
|
||||||
|
#define SDR_MIN_LUMINANCE 0.2
|
||||||
|
#define SDR_MAX_LUMINANCE 80.0
|
||||||
|
#define HDR_MIN_LUMINANCE 0.005
|
||||||
|
#define HDR_MAX_LUMINANCE 10000.0
|
||||||
|
#define HLG_MAX_LUMINANCE 1000.0
|
||||||
|
|
||||||
|
#define M_E 2.718281828459045
|
||||||
|
|
||||||
|
#endif
|
||||||
10
src/render/shaders/glsl/defines.h
Normal file
10
src/render/shaders/glsl/defines.h
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
// DO NOT EDIT. Will be overwritten in runtime
|
||||||
|
#define USE_RGBA 1
|
||||||
|
#define USE_DISCARD 1
|
||||||
|
#define USE_TINT 1
|
||||||
|
#define USE_ROUNDING 1
|
||||||
|
#define USE_CM 1
|
||||||
|
#define USE_TONEMAP 1
|
||||||
|
#define USE_SDR_MOD 1
|
||||||
|
#define USE_BLUR 1
|
||||||
|
#define USE_ICC 1
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
uniform bool discardOpaque;
|
|
||||||
uniform bool discardAlpha;
|
|
||||||
uniform float discardAlphaValue;
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
pixColor = doColorManagement(pixColor, sourceTF, targetTF, targetPrimariesXYZ);
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
if (discardOpaque && pixColor.a * alpha == 1.0)
|
|
||||||
discard;
|
|
||||||
|
|
||||||
if (discardAlpha && pixColor.a <= discardAlphaValue)
|
|
||||||
discard;
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
pixColor = rounding(pixColor);
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
pixColor = saturate(pixColor, dstxyz, sdrSaturation);
|
|
||||||
pixColor.rgb *= sdrBrightnessMultiplier;
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
pixColor.rgb = pixColor.rgb * tint;
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
pixColor = tonemap(pixColor, dstxyz);
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
#version 300 es
|
#version 300 es
|
||||||
|
|
||||||
|
#define ALLOW_INCLUDES
|
||||||
#extension GL_ARB_shading_language_include : enable
|
#extension GL_ARB_shading_language_include : enable
|
||||||
#extension GL_OES_EGL_image_external_essl3 : require
|
#extension GL_OES_EGL_image_external_essl3 : require
|
||||||
|
|
||||||
|
|
@ -8,6 +9,10 @@ in vec2 v_texcoord;
|
||||||
uniform samplerExternalOES tex;
|
uniform samplerExternalOES tex;
|
||||||
uniform float alpha;
|
uniform float alpha;
|
||||||
|
|
||||||
|
uniform float radius;
|
||||||
|
uniform float roundingPower;
|
||||||
|
uniform vec2 topLeft;
|
||||||
|
uniform vec2 fullSize;
|
||||||
#include "rounding.glsl"
|
#include "rounding.glsl"
|
||||||
|
|
||||||
uniform int discardOpaque;
|
uniform int discardOpaque;
|
||||||
|
|
@ -32,7 +37,7 @@ void main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (radius > 0.0)
|
if (radius > 0.0)
|
||||||
pixColor = rounding(pixColor);
|
pixColor = rounding(pixColor, radius, roundingPower, topLeft, fullSize);
|
||||||
|
|
||||||
fragColor = pixColor * alpha;
|
fragColor = pixColor * alpha;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
#include "get_rgbx_pixel.glsl"
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
vec4 pixColor = texture(tex, v_texcoord);
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
vec4 pixColor = vec4(texture(tex, v_texcoord).rgb, 1.0);
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
#include "primaries_xyz_uniform.glsl"
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
const mat3 targetPrimariesXYZ = mat3(0.0);
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
uniform mat3 targetPrimariesXYZ;
|
|
||||||
|
|
@ -1,17 +1,27 @@
|
||||||
#version 300 es
|
#version 300 es
|
||||||
|
|
||||||
|
#define ALLOW_INCLUDES
|
||||||
#extension GL_ARB_shading_language_include : enable
|
#extension GL_ARB_shading_language_include : enable
|
||||||
|
#include "defines.h"
|
||||||
|
|
||||||
precision highp float;
|
precision highp float;
|
||||||
in vec4 v_color;
|
in vec4 v_color;
|
||||||
|
|
||||||
|
#if USE_ROUNDING
|
||||||
|
uniform float radius;
|
||||||
|
uniform float roundingPower;
|
||||||
|
uniform vec2 topLeft;
|
||||||
|
uniform vec2 fullSize;
|
||||||
#include "rounding.glsl"
|
#include "rounding.glsl"
|
||||||
|
#endif
|
||||||
|
|
||||||
layout(location = 0) out vec4 fragColor;
|
layout(location = 0) out vec4 fragColor;
|
||||||
void main() {
|
void main() {
|
||||||
vec4 pixColor = v_color;
|
vec4 pixColor = v_color;
|
||||||
|
|
||||||
if (radius > 0.0)
|
#if USE_ROUNDING
|
||||||
pixColor = rounding(pixColor);
|
pixColor = rounding(pixColor, radius, roundingPower, topLeft, fullSize);
|
||||||
|
#endif
|
||||||
|
|
||||||
fragColor = pixColor;
|
fragColor = pixColor;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,10 @@
|
||||||
|
#ifndef ROUNDING_GLSL
|
||||||
|
#define ROUNDING_GLSL
|
||||||
// smoothing constant for the edge: more = blurrier, but smoother
|
// smoothing constant for the edge: more = blurrier, but smoother
|
||||||
#define M_PI 3.1415926535897932384626433832795
|
#define M_PI 3.1415926535897932384626433832795
|
||||||
#define SMOOTHING_CONSTANT (M_PI / 5.34665792551)
|
#define SMOOTHING_CONSTANT (M_PI / 5.34665792551)
|
||||||
|
|
||||||
uniform float radius;
|
vec4 rounding(vec4 color, float radius, float roundingPower, vec2 topLeft, vec2 fullSize) {
|
||||||
uniform float roundingPower;
|
|
||||||
uniform vec2 topLeft;
|
|
||||||
uniform vec2 fullSize;
|
|
||||||
|
|
||||||
vec4 rounding(vec4 color) {
|
|
||||||
vec2 pixCoord = vec2(gl_FragCoord);
|
vec2 pixCoord = vec2(gl_FragCoord);
|
||||||
pixCoord -= topLeft + fullSize * 0.5;
|
pixCoord -= topLeft + fullSize * 0.5;
|
||||||
pixCoord *= vec2(lessThan(pixCoord, vec2(0.0))) * -2.0 + 1.0;
|
pixCoord *= vec2(lessThan(pixCoord, vec2(0.0))) * -2.0 + 1.0;
|
||||||
|
|
@ -27,3 +24,4 @@ vec4 rounding(vec4 color) {
|
||||||
|
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
uniform float sdrSaturation;
|
|
||||||
uniform float sdrBrightnessMultiplier;
|
|
||||||
|
|
||||||
vec4 saturate(vec4 color, mat3 primaries, float saturation) {
|
|
||||||
if (saturation == 1.0)
|
|
||||||
return color;
|
|
||||||
vec3 brightness = vec3(primaries[1][0], primaries[1][1], primaries[1][2]);
|
|
||||||
float Y = dot(color.rgb, brightness);
|
|
||||||
return vec4(mix(vec3(Y), color.rgb, saturation), color[3]);
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
#version 300 es
|
#version 300 es
|
||||||
|
#define ALLOW_INCLUDES
|
||||||
#extension GL_ARB_shading_language_include : enable
|
#extension GL_ARB_shading_language_include : enable
|
||||||
|
|
||||||
|
#include "defines.h"
|
||||||
|
|
||||||
precision highp float;
|
precision highp float;
|
||||||
in vec4 v_color;
|
in vec4 v_color;
|
||||||
in vec2 v_texcoord;
|
in vec2 v_texcoord;
|
||||||
|
|
@ -17,77 +20,38 @@ uniform float roundingPower;
|
||||||
uniform float range;
|
uniform float range;
|
||||||
uniform float shadowPower;
|
uniform float shadowPower;
|
||||||
|
|
||||||
float pixAlphaRoundedDistance(float distanceToCorner) {
|
#if USE_CM
|
||||||
if (distanceToCorner > radius) {
|
#include "cm_helpers.glsl"
|
||||||
return 0.0;
|
#include "CM.glsl"
|
||||||
}
|
#endif
|
||||||
|
|
||||||
if (distanceToCorner > radius - range) {
|
#include "shadow.glsl"
|
||||||
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;
|
layout(location = 0) out vec4 fragColor;
|
||||||
void main() {
|
void main() {
|
||||||
|
|
||||||
vec4 pixColor = v_color;
|
vec4 pixColor = v_color;
|
||||||
float originalAlpha = pixColor[3];
|
|
||||||
|
|
||||||
bool done = false;
|
fragColor = getShadow(pixColor, v_texcoord, radius, roundingPower, topLeft, fullSize, range, shadowPower, bottomRight
|
||||||
|
#if USE_CM
|
||||||
vec2 pixCoord = fullSize * v_texcoord;
|
,
|
||||||
|
sourceTF, targetTF, convertMatrix, srcTFRange, dstTFRange
|
||||||
// ok, now we check the distance to a border.
|
#if USE_ICC
|
||||||
|
,
|
||||||
if (pixCoord[0] < topLeft[0]) {
|
iccLut3D, iccLutSize
|
||||||
if (pixCoord[1] < topLeft[1]) {
|
#else
|
||||||
// top left
|
#if USE_TONEMAP || USE_SDR_MOD
|
||||||
pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(modifiedLength(pixCoord - topLeft));
|
,
|
||||||
done = true;
|
targetPrimariesXYZ
|
||||||
} else if (pixCoord[1] > bottomRight[1]) {
|
#endif
|
||||||
// bottom left
|
#if USE_TONEMAP
|
||||||
pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(modifiedLength(pixCoord - vec2(topLeft[0], bottomRight[1])));
|
,
|
||||||
done = true;
|
maxLuminance, dstMaxLuminance, dstRefLuminance, srcRefLuminance
|
||||||
}
|
#endif
|
||||||
} else if (pixCoord[0] > bottomRight[0]) {
|
#if USE_SDR_MOD
|
||||||
if (pixCoord[1] < topLeft[1]) {
|
,
|
||||||
// top right
|
sdrSaturation, sdrBrightnessMultiplier
|
||||||
pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(modifiedLength(pixCoord - vec2(bottomRight[0], topLeft[1])));
|
#endif
|
||||||
done = true;
|
#endif
|
||||||
} else if (pixCoord[1] > bottomRight[1]) {
|
#endif
|
||||||
// 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];
|
|
||||||
|
|
||||||
fragColor = pixColor;
|
|
||||||
}
|
}
|
||||||
126
src/render/shaders/glsl/shadow.glsl
Normal file
126
src/render/shaders/glsl/shadow.glsl
Normal file
|
|
@ -0,0 +1,126 @@
|
||||||
|
#ifndef ALLOW_INCLUDES
|
||||||
|
#define ALLOW_INCLUDES
|
||||||
|
#extension GL_ARB_shading_language_include : enable
|
||||||
|
#endif
|
||||||
|
#ifndef SHADOW_GLSL
|
||||||
|
#define SHADOW_GLSL
|
||||||
|
|
||||||
|
#include "cm_helpers.glsl"
|
||||||
|
|
||||||
|
float pixAlphaRoundedDistance(float distanceToCorner, float radius, float range, float shadowPower) {
|
||||||
|
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, float roundingPower) {
|
||||||
|
return pow(pow(abs(a.x), roundingPower) + pow(abs(a.y), roundingPower), 1.0 / roundingPower);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 getShadow(vec4 pixColor, vec2 v_texcoord, float radius, float roundingPower, vec2 topLeft, vec2 fullSize, float range, float shadowPower, vec2 bottomRight
|
||||||
|
#if USE_CM
|
||||||
|
,
|
||||||
|
int sourceTF, int targetTF, mat3 convertMatrix, vec2 srcTFRange, vec2 dstTFRange
|
||||||
|
#if USE_ICC
|
||||||
|
,
|
||||||
|
highp sampler3D iccLut3D, float iccLutSize
|
||||||
|
#else
|
||||||
|
#if USE_TONEMAP || USE_SDR_MOD
|
||||||
|
,
|
||||||
|
mat3 targetPrimariesXYZ
|
||||||
|
#endif
|
||||||
|
#if USE_TONEMAP
|
||||||
|
,
|
||||||
|
float maxLuminance, float dstMaxLuminance, float dstRefLuminance, float srcRefLuminance
|
||||||
|
#endif
|
||||||
|
#if USE_SDR_MOD
|
||||||
|
,
|
||||||
|
float sdrSaturation, float sdrBrightnessMultiplier
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
|
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, roundingPower), radius, range, shadowPower);
|
||||||
|
done = true;
|
||||||
|
} else if (pixCoord[1] > bottomRight[1]) {
|
||||||
|
// bottom left
|
||||||
|
pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(modifiedLength(pixCoord - vec2(topLeft[0], bottomRight[1]), roundingPower), radius, range, shadowPower);
|
||||||
|
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]), roundingPower), radius, range, shadowPower);
|
||||||
|
done = true;
|
||||||
|
} else if (pixCoord[1] > bottomRight[1]) {
|
||||||
|
// bottom right
|
||||||
|
pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(modifiedLength(pixCoord - bottomRight, roundingPower), radius, range, shadowPower);
|
||||||
|
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 pixColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
// premultiply
|
||||||
|
pixColor.rgb *= pixColor[3];
|
||||||
|
|
||||||
|
#if USE_CM
|
||||||
|
pixColor = doColorManagement(pixColor, sourceTF, targetTF, convertMatrix, srcTFRange, dstTFRange
|
||||||
|
#if USE_ICC
|
||||||
|
,
|
||||||
|
iccLut3D, iccLutSize
|
||||||
|
#else
|
||||||
|
#if USE_TONEMAP || USE_SDR_MOD
|
||||||
|
,
|
||||||
|
targetPrimariesXYZ
|
||||||
|
#endif
|
||||||
|
#if USE_TONEMAP
|
||||||
|
,
|
||||||
|
maxLuminance, dstMaxLuminance, dstRefLuminance, srcRefLuminance
|
||||||
|
#endif
|
||||||
|
#if USE_SDR_MOD
|
||||||
|
,
|
||||||
|
sdrSaturation, sdrBrightnessMultiplier
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return pixColor;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -1,25 +1,104 @@
|
||||||
#version 300 es
|
#version 300 es
|
||||||
|
#define ALLOW_INCLUDES
|
||||||
#extension GL_ARB_shading_language_include : enable
|
#extension GL_ARB_shading_language_include : enable
|
||||||
|
|
||||||
|
#include "defines.h"
|
||||||
|
|
||||||
precision highp float;
|
precision highp float;
|
||||||
in vec2 v_texcoord;
|
in vec2 v_texcoord;
|
||||||
uniform sampler2D tex;
|
uniform sampler2D tex;
|
||||||
|
#if USE_BLUR
|
||||||
|
uniform vec2 uvSize;
|
||||||
|
uniform vec2 uvOffset;
|
||||||
|
uniform sampler2D blurredBG;
|
||||||
|
#endif
|
||||||
|
|
||||||
uniform float alpha;
|
uniform float alpha;
|
||||||
|
|
||||||
#include "discard.glsl"
|
#if USE_DISCARD
|
||||||
#include "tint.glsl"
|
uniform bool discardOpaque;
|
||||||
|
uniform bool discardAlpha;
|
||||||
|
uniform float discardAlphaValue;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_TINT
|
||||||
|
uniform vec3 tint;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_ROUNDING
|
||||||
|
uniform float radius;
|
||||||
|
uniform float roundingPower;
|
||||||
|
uniform vec2 topLeft;
|
||||||
|
uniform vec2 fullSize;
|
||||||
#include "rounding.glsl"
|
#include "rounding.glsl"
|
||||||
#include "surface_CM.glsl"
|
#endif
|
||||||
|
|
||||||
|
#if USE_CM
|
||||||
|
uniform int sourceTF; // eTransferFunction
|
||||||
|
uniform int targetTF; // eTransferFunction
|
||||||
|
|
||||||
|
#if USE_TONEMAP || USE_SDR_MOD
|
||||||
|
uniform mat3 targetPrimariesXYZ;
|
||||||
|
#else
|
||||||
|
const mat3 targetPrimariesXYZ = mat3(0.0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "CM.glsl"
|
||||||
|
#endif
|
||||||
|
|
||||||
layout(location = 0) out vec4 fragColor;
|
layout(location = 0) out vec4 fragColor;
|
||||||
void main() {
|
void main() {
|
||||||
#include "get_rgb_pixel.glsl"
|
#if USE_RGBA
|
||||||
|
vec4 pixColor = texture(tex, v_texcoord);
|
||||||
|
#else
|
||||||
|
vec4 pixColor = vec4(texture(tex, v_texcoord).rgb, 1.0);
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "do_discard.glsl"
|
#if USE_DISCARD && !USE_BLUR
|
||||||
#include "do_CM.glsl"
|
if (discardOpaque && pixColor.a * alpha == 1.0)
|
||||||
#include "do_tint.glsl"
|
discard;
|
||||||
#include "do_rounding.glsl"
|
|
||||||
|
if (discardAlpha && pixColor.a <= discardAlphaValue)
|
||||||
|
discard;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_CM
|
||||||
|
pixColor = doColorManagement(pixColor, sourceTF, targetTF, convertMatrix, srcTFRange, dstTFRange
|
||||||
|
#if USE_ICC
|
||||||
|
,
|
||||||
|
iccLut3D, iccLutSize
|
||||||
|
#else
|
||||||
|
#if USE_TONEMAP || USE_SDR_MOD
|
||||||
|
,
|
||||||
|
targetPrimariesXYZ
|
||||||
|
#endif
|
||||||
|
#if USE_TONEMAP
|
||||||
|
,
|
||||||
|
maxLuminance, dstMaxLuminance, dstRefLuminance, srcRefLuminance
|
||||||
|
#endif
|
||||||
|
#if USE_SDR_MOD
|
||||||
|
,
|
||||||
|
sdrSaturation, sdrBrightnessMultiplier
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_TINT
|
||||||
|
pixColor.rgb = pixColor.rgb * tint;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_ROUNDING
|
||||||
|
pixColor = rounding(pixColor, radius, roundingPower, topLeft, fullSize);
|
||||||
|
#endif
|
||||||
|
#if USE_BLUR
|
||||||
|
#if USE_DISCARD
|
||||||
|
pixColor = mix(pixColor, vec4(mix(texture(blurredBG, v_texcoord * uvSize + uvOffset).rgb, pixColor.rgb, pixColor.a), 1.0),
|
||||||
|
discardAlpha && (pixColor.a <= discardAlphaValue) ? 0.0 : 1.0);
|
||||||
|
#else
|
||||||
|
pixColor = vec4(mix(texture(blurredBG, v_texcoord * uvSize + uvOffset).rgb, pixColor.rgb, pixColor.a), 1.0);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
fragColor = pixColor * alpha;
|
fragColor = pixColor * alpha;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
uniform int sourceTF; // eTransferFunction
|
|
||||||
uniform int targetTF; // eTransferFunction
|
|
||||||
#include "primaries_xyz.glsl"
|
|
||||||
#include "CM.glsl"
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
uniform vec3 tint;
|
|
||||||
|
|
@ -1,17 +1,15 @@
|
||||||
uniform float maxLuminance;
|
#ifndef ALLOW_INCLUDES
|
||||||
uniform float dstMaxLuminance;
|
#define ALLOW_INCLUDES
|
||||||
uniform float dstRefLuminance;
|
#extension GL_ARB_shading_language_include : enable
|
||||||
|
#endif
|
||||||
|
#include "constants.h"
|
||||||
|
|
||||||
const mat3 BT2020toLMS = mat3(
|
const mat3 BT2020toLMS = mat3(0.3592, 0.6976, -0.0358, -0.1922, 1.1004, 0.0755, 0.0070, 0.0749, 0.8434);
|
||||||
0.3592, 0.6976, -0.0358,
|
|
||||||
-0.1922, 1.1004, 0.0755,
|
|
||||||
0.0070, 0.0749, 0.8434
|
|
||||||
);
|
|
||||||
//const mat3 LMStoBT2020 = inverse(BT2020toLMS);
|
//const mat3 LMStoBT2020 = inverse(BT2020toLMS);
|
||||||
const mat3 LMStoBT2020 = mat3(
|
const mat3 LMStoBT2020 = mat3( //
|
||||||
2.0701800566956135096, -1.3264568761030210255, 0.20661600684785517081,
|
2.0701800566956135096, -1.3264568761030210255, 0.20661600684785517081, //
|
||||||
0.36498825003265747974, 0.68046736285223514102, -0.045421753075853231409,
|
0.36498825003265747974, 0.68046736285223514102, -0.045421753075853231409, //
|
||||||
-0.049595542238932107896, -0.049421161186757487412, 1.1879959417328034394
|
-0.049595542238932107896, -0.049421161186757487412, 1.1879959417328034394 //
|
||||||
);
|
);
|
||||||
|
|
||||||
// const mat3 ICtCpPQ = transpose(mat3(
|
// const mat3 ICtCpPQ = transpose(mat3(
|
||||||
|
|
@ -19,16 +17,16 @@ const mat3 LMStoBT2020 = mat3(
|
||||||
// 6610.0, -13613.0, 7003.0,
|
// 6610.0, -13613.0, 7003.0,
|
||||||
// 17933.0, -17390.0, -543.0
|
// 17933.0, -17390.0, -543.0
|
||||||
// ) / 4096.0);
|
// ) / 4096.0);
|
||||||
const mat3 ICtCpPQ = mat3(
|
const mat3 ICtCpPQ = mat3( //
|
||||||
0.5, 1.61376953125, 4.378173828125,
|
0.5, 1.61376953125, 4.378173828125, //
|
||||||
0.5, -3.323486328125, -4.24560546875,
|
0.5, -3.323486328125, -4.24560546875, //
|
||||||
0.0, 1.709716796875, -0.132568359375
|
0.0, 1.709716796875, -0.132568359375 //
|
||||||
);
|
);
|
||||||
//const mat3 ICtCpPQInv = inverse(ICtCpPQ);
|
//const mat3 ICtCpPQInv = inverse(ICtCpPQ);
|
||||||
const mat3 ICtCpPQInv = mat3(
|
const mat3 ICtCpPQInv = mat3( //
|
||||||
1.0, 1.0, 1.0,
|
1.0, 1.0, 1.0, //
|
||||||
0.0086090370379327566, -0.0086090370379327566, 0.560031335710679118,
|
0.0086090370379327566, -0.0086090370379327566, 0.560031335710679118, //
|
||||||
0.11102962500302595656, -0.11102962500302595656, -0.32062717498731885185
|
0.11102962500302595656, -0.11102962500302595656, -0.32062717498731885185 //
|
||||||
);
|
);
|
||||||
|
|
||||||
// unused for now
|
// unused for now
|
||||||
|
|
@ -39,7 +37,7 @@ const mat3 ICtCpPQInv = mat3(
|
||||||
// ) / 4096.0);
|
// ) / 4096.0);
|
||||||
// const mat3 ICtCpHLGInv = inverse(ICtCpHLG);
|
// const mat3 ICtCpHLGInv = inverse(ICtCpHLG);
|
||||||
|
|
||||||
vec4 tonemap(vec4 color, mat3 dstXYZ) {
|
vec4 tonemap(vec4 color, mat3 dstXYZ, float maxLuminance, float dstMaxLuminance, float dstRefLuminance, float srcRefLuminance) {
|
||||||
if (maxLuminance < dstMaxLuminance * 1.01)
|
if (maxLuminance < dstMaxLuminance * 1.01)
|
||||||
return vec4(clamp(color.rgb, vec3(0.0), vec3(dstMaxLuminance)), color[3]);
|
return vec4(clamp(color.rgb, vec3(0.0), vec3(dstMaxLuminance)), color[3]);
|
||||||
|
|
||||||
|
|
@ -50,10 +48,7 @@ vec4 tonemap(vec4 color, mat3 dstXYZ) {
|
||||||
vec3 ICtCp = ICtCpPQ * lms;
|
vec3 ICtCp = ICtCpPQ * lms;
|
||||||
|
|
||||||
float E = pow(clamp(ICtCp[0], 0.0, 1.0), PQ_INV_M2);
|
float E = pow(clamp(ICtCp[0], 0.0, 1.0), PQ_INV_M2);
|
||||||
float luminance = pow(
|
float luminance = pow((max(E - PQ_C1, 0.0)) / (PQ_C2 - PQ_C3 * E), PQ_INV_M1) * HDR_MAX_LUMINANCE;
|
||||||
(max(E - PQ_C1, 0.0)) / (PQ_C2 - PQ_C3 * E),
|
|
||||||
PQ_INV_M1
|
|
||||||
) * HDR_MAX_LUMINANCE;
|
|
||||||
|
|
||||||
float linearPart = min(luminance, dstRefLuminance);
|
float linearPart = min(luminance, dstRefLuminance);
|
||||||
float luminanceAboveRef = max(luminance - dstRefLuminance, 0.0);
|
float luminanceAboveRef = max(luminance - dstRefLuminance, 0.0);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue