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")
|
||||
find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION})
|
||||
find_package(glslang CONFIG REQUIRED)
|
||||
|
||||
set(AQUAMARINE_MINIMUM_VERSION 0.9.3)
|
||||
set(HYPRLANG_MINIMUM_VERSION 0.6.7)
|
||||
|
|
@ -479,9 +480,9 @@ function(protocolWayland)
|
|||
endfunction()
|
||||
|
||||
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()
|
||||
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()
|
||||
|
||||
pkg_check_modules(hyprland_protocols_dep hyprland-protocols>=0.6.4)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
epoll-shim,
|
||||
git,
|
||||
glaze-hyprland,
|
||||
glslang,
|
||||
gtest,
|
||||
hyprcursor,
|
||||
hyprgraphics,
|
||||
|
|
@ -173,6 +174,7 @@ customStdenv.mkDerivation (finalAttrs: {
|
|||
cairo
|
||||
git
|
||||
glaze-hyprland
|
||||
glslang
|
||||
gtest
|
||||
hyprcursor
|
||||
hyprgraphics
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ echo 'static const std::map<std::string, std::string> SHADERS = {' >> ./src/rend
|
|||
for filename in `ls ${SHADERS_SRC}`; do
|
||||
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 "#include \"./${filename}.inc\"" >> ./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,
|
||||
.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:
|
||||
|
|
|
|||
|
|
@ -800,6 +800,7 @@ CConfigManager::CConfigManager() {
|
|||
registerConfigVar("render:cm_sdr_eotf", {"default"});
|
||||
registerConfigVar("render:commit_timing_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_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) {
|
||||
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";
|
||||
else
|
||||
return format == FORMAT_JSON ? "{\"ok\": false}" : "error";
|
||||
|
|
@ -2076,8 +2081,8 @@ CHyprCtl::CHyprCtl() {
|
|||
registerCommand(SHyprCtlCommand{"locked", true, getIsLocked});
|
||||
registerCommand(SHyprCtlCommand{"descriptions", true, getDescriptions});
|
||||
registerCommand(SHyprCtlCommand{"submap", true, submapRequest});
|
||||
registerCommand(SHyprCtlCommand{.name = "reloadshaders", .exact = true, .fn = reloadShaders});
|
||||
|
||||
registerCommand(SHyprCtlCommand{.name = "reloadshaders", .exact = false, .fn = reloadShaders});
|
||||
registerCommand(SHyprCtlCommand{"monitors", false, monitorsRequest});
|
||||
registerCommand(SHyprCtlCommand{"reload", false, reloadRequest});
|
||||
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));
|
||||
}
|
||||
|
||||
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) {
|
||||
auto n = drmGetFormatName(drm);
|
||||
|
||||
|
|
|
|||
|
|
@ -53,8 +53,6 @@ namespace NFormatUtils {
|
|||
bool isFormatOpaque(DRMFormat drm);
|
||||
int pixelsPerBlock(const SPixelFormat* const fmt);
|
||||
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 drmModifierName(uint64_t mod);
|
||||
DRMFormat alphaFormat(DRMFormat prevFormat);
|
||||
|
|
|
|||
|
|
@ -1579,10 +1579,20 @@ Vector2D CMonitor::middle() {
|
|||
return m_position + m_size / 2.f;
|
||||
}
|
||||
|
||||
const Mat3x3& CMonitor::getTransformMatrix() {
|
||||
return m_projMatrix;
|
||||
}
|
||||
|
||||
const Mat3x3& CMonitor::getScaleMatrix() {
|
||||
return m_projOutputMatrix;
|
||||
}
|
||||
|
||||
void CMonitor::updateMatrix() {
|
||||
m_projMatrix = Mat3x3::identity();
|
||||
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_projOutputMatrix = Mat3x3::outputProjection(m_pixelSize, HYPRUTILS_TRANSFORM_NORMAL);
|
||||
}
|
||||
|
||||
WORKSPACEID CMonitor::activeWorkspaceID() {
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ class CMonitor {
|
|||
bool m_scheduledRecalc = false;
|
||||
wl_output_transform m_transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
float m_xwaylandScale = 1.f;
|
||||
Mat3x3 m_projMatrix;
|
||||
|
||||
std::optional<Vector2D> m_forceSize;
|
||||
SP<Aquamarine::SOutputMode> m_currentMode;
|
||||
SP<Aquamarine::CSwapchain> m_cursorSwapchain;
|
||||
|
|
@ -303,7 +303,6 @@ class CMonitor {
|
|||
void setSpecialWorkspace(const WORKSPACEID& id);
|
||||
void moveTo(const Vector2D& pos);
|
||||
Vector2D middle();
|
||||
void updateMatrix();
|
||||
WORKSPACEID activeWorkspaceID();
|
||||
WORKSPACEID activeSpecialWorkspaceID();
|
||||
CBox logicalBox();
|
||||
|
|
@ -335,6 +334,10 @@ class CMonitor {
|
|||
bool inHDR();
|
||||
bool gammaRampsInUse();
|
||||
|
||||
//
|
||||
const Mat3x3& getTransformMatrix();
|
||||
const Mat3x3& getScaleMatrix();
|
||||
|
||||
/// Has an active workspace with a real fullscreen window (includes special workspace)
|
||||
bool inFullscreenMode();
|
||||
/// 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;
|
||||
}
|
||||
|
||||
Mat3x3 m_projMatrix;
|
||||
|
||||
private:
|
||||
void updateMatrix();
|
||||
Mat3x3 m_projOutputMatrix;
|
||||
|
||||
void setupDefaultWS(const SMonitorRule&);
|
||||
WORKSPACEID findAvailableDefaultWS();
|
||||
void commitDPMSState(bool state);
|
||||
|
|
|
|||
|
|
@ -26,7 +26,10 @@ std::string NTransferFunction::toString(eTF tf) {
|
|||
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 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);
|
||||
std::string toString(eTF tf);
|
||||
|
||||
eTF fromConfig();
|
||||
eTF fromConfig(bool useICC = false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -322,18 +322,22 @@ namespace NColorManagement {
|
|||
|
||||
using PImageDescription = WP<const CImageDescription>;
|
||||
|
||||
static const auto DEFAULT_IMAGE_DESCRIPTION = CImageDescription::from(SImageDescription{.transferFunction = NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22,
|
||||
.primariesNameSet = true,
|
||||
.primariesNamed = NColorManagement::CM_PRIMARIES_SRGB,
|
||||
.primaries = NColorManagement::getPrimaries(NColorManagement::CM_PRIMARIES_SRGB),
|
||||
.luminances = {.min = SDR_MIN_LUMINANCE, .max = 80, .reference = 80}});
|
||||
static const auto DEFAULT_IMAGE_DESCRIPTION = CImageDescription::from(SImageDescription{
|
||||
.transferFunction = NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22,
|
||||
.primariesNameSet = true,
|
||||
.primariesNamed = NColorManagement::CM_PRIMARIES_SRGB,
|
||||
.primaries = NColorManagement::getPrimaries(NColorManagement::CM_PRIMARIES_SRGB),
|
||||
.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,
|
||||
.primariesNameSet = true,
|
||||
.primariesNamed = NColorManagement::CM_PRIMARIES_BT2020,
|
||||
.primaries = NColorManagement::getPrimaries(NColorManagement::CM_PRIMARIES_BT2020),
|
||||
.luminances = {.min = HDR_MIN_LUMINANCE, .max = 10000, .reference = 203},
|
||||
});
|
||||
|
||||
static const auto DEFAULT_HDR_IMAGE_DESCRIPTION = CImageDescription::from(SImageDescription{.transferFunction = NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ,
|
||||
.primariesNameSet = true,
|
||||
.primariesNamed = NColorManagement::CM_PRIMARIES_BT2020,
|
||||
.primaries = NColorManagement::getPrimaries(NColorManagement::CM_PRIMARIES_BT2020),
|
||||
.luminances = {.min = HDR_MIN_LUMINANCE, .max = 10000, .reference = 203}});
|
||||
;
|
||||
static const auto SCRGB_IMAGE_DESCRIPTION = CImageDescription::from(SImageDescription{
|
||||
.transferFunction = NColorManagement::CM_TRANSFER_FUNCTION_EXT_LINEAR,
|
||||
.windowsScRGB = true,
|
||||
|
|
@ -342,6 +346,6 @@ namespace NColorManagement {
|
|||
.primaries = NColorPrimaries::BT709,
|
||||
.luminances = {.reference = 203},
|
||||
});
|
||||
;
|
||||
|
||||
}
|
||||
static const auto LINEAR_IMAGE_DESCRIPTION = SCRGB_IMAGE_DESCRIPTION; // TODO any reason to use something different?
|
||||
}
|
||||
|
|
|
|||
|
|
@ -162,8 +162,9 @@ void CScreenshareFrame::renderMonitor() {
|
|||
if (!g_pHyprOpenGL->m_monitorRenderResources.contains(PMONITOR))
|
||||
return; // wtf?
|
||||
|
||||
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.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.
|
||||
g_pHyprOpenGL->pushMonitorTransformEnabled(true);
|
||||
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->popMonitorTransformEnabled();
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -31,6 +31,7 @@
|
|||
|
||||
#include "../debug/TracyDefines.hpp"
|
||||
#include "../protocols/core/Compositor.hpp"
|
||||
#include "render/ShaderLoader.hpp"
|
||||
|
||||
struct gbm_device;
|
||||
class CHyprRenderer;
|
||||
|
|
@ -87,54 +88,23 @@ enum eMonitorExtraRenderFBs : uint8_t {
|
|||
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 {
|
||||
ePreparedFragmentShader id;
|
||||
const char* file;
|
||||
Render::ePreparedFragmentShader id;
|
||||
const char* file;
|
||||
};
|
||||
|
||||
struct SPreparedShaders {
|
||||
SPreparedShaders() {
|
||||
for (auto& f : frag) {
|
||||
f = makeShared<CShader>();
|
||||
}
|
||||
}
|
||||
// SPreparedShaders() {
|
||||
// for (auto& f : frag) {
|
||||
// f = makeShared<CShader>();
|
||||
// }
|
||||
// }
|
||||
|
||||
std::string TEXVERTSRC;
|
||||
std::string TEXVERTSRC320;
|
||||
std::array<SP<CShader>, SH_FRAG_LAST> frag;
|
||||
std::map<uint8_t, SP<CShader>> fragVariants;
|
||||
std::string TEXVERTSRC;
|
||||
std::string TEXVERTSRC320;
|
||||
// std::array<SP<CShader>, SH_FRAG_LAST> frag;
|
||||
// std::map<uint8_t, SP<CShader>> fragVariants;
|
||||
std::array<std::map<Render::ShaderFeatureFlags, SP<CShader>>, Render::SH_FRAG_LAST> fragVariants;
|
||||
};
|
||||
|
||||
struct SMonitorRenderData {
|
||||
|
|
@ -242,6 +212,8 @@ class CHyprOpenGLImpl {
|
|||
bool cmBackToSRGB = false;
|
||||
bool noCM = false;
|
||||
bool finalMonitorCM = false;
|
||||
SP<CMonitor> cmBackToSRGBSource;
|
||||
SP<CTexture> blurredBG;
|
||||
};
|
||||
|
||||
struct SBorderRenderData {
|
||||
|
|
@ -316,18 +288,15 @@ class CHyprOpenGLImpl {
|
|||
std::vector<uint64_t> getDRMFormatModifiers(DRMFormat format);
|
||||
EGLImageKHR createEGLImage(const Aquamarine::SDMABUFAttrs& attrs);
|
||||
|
||||
bool initShaders();
|
||||
bool initShaders(const std::string& path = "");
|
||||
|
||||
WP<CShader> useShader(WP<CShader> prog);
|
||||
|
||||
void ensureLockTexturesRendered(bool load);
|
||||
|
||||
bool explicitSyncSupported();
|
||||
WP<CShader> getSurfaceShader(uint8_t features);
|
||||
WP<CShader> getShaderVariant(Render::ePreparedFragmentShader frag, Render::ShaderFeatureFlags features = 0);
|
||||
|
||||
bool m_shadersInitialized = false;
|
||||
SP<SPreparedShaders> m_shaders;
|
||||
std::map<std::string, std::string> m_includes;
|
||||
|
||||
SCurrentRenderData m_renderData;
|
||||
|
||||
|
|
@ -431,6 +400,7 @@ class CHyprOpenGLImpl {
|
|||
void initEGL(bool gbm);
|
||||
EGLDeviceEXT eglDeviceFromDRMFD(int drmFD);
|
||||
void initAssets();
|
||||
void ensureLockTexturesRendered(bool load);
|
||||
void initMissingAssetTexture();
|
||||
void requestBackgroundResource();
|
||||
|
||||
|
|
@ -454,6 +424,8 @@ class CHyprOpenGLImpl {
|
|||
void renderRectInternal(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);
|
||||
WP<CShader> renderToOutputInternal();
|
||||
WP<CShader> renderToFBInternal(const STextureRenderData& data, eTextureType texType, const CBox& newBox);
|
||||
void renderTextureInternal(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);
|
||||
m_framebuffer.m_fbAllocated = true;
|
||||
m_framebuffer.m_size = buffer->size;
|
||||
m_framebuffer.m_drmFormat = dma.format;
|
||||
m_framebuffer.bind();
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_rbo);
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#include "../event/EventBus.hpp"
|
||||
#include "helpers/CursorShapes.hpp"
|
||||
#include "helpers/Monitor.hpp"
|
||||
#include "helpers/cm/ColorManagement.hpp"
|
||||
#include "pass/TexPassElement.hpp"
|
||||
#include "pass/ClearPassElement.hpp"
|
||||
#include "pass/RectPassElement.hpp"
|
||||
|
|
@ -41,7 +42,6 @@
|
|||
#include "../protocols/ColorManagement.hpp"
|
||||
#include "../protocols/types/ContentType.hpp"
|
||||
#include "../helpers/MiscFunctions.hpp"
|
||||
#include "../event/EventBus.hpp"
|
||||
#include "render/OpenGL.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) {
|
||||
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();
|
||||
|
|
@ -2200,10 +2273,8 @@ std::tuple<float, float, float> CHyprRenderer::getRenderTimes(PHLMONITOR pMonito
|
|||
float maxRenderTime = 0;
|
||||
float minRenderTime = 9999;
|
||||
for (auto const& rt : POVERLAY->m_lastRenderTimes) {
|
||||
if (rt > maxRenderTime)
|
||||
maxRenderTime = rt;
|
||||
if (rt < minRenderTime)
|
||||
minRenderTime = rt;
|
||||
maxRenderTime = std::max(rt, maxRenderTime);
|
||||
minRenderTime = std::min(rt, minRenderTime);
|
||||
avgRenderTime += rt;
|
||||
}
|
||||
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)));
|
||||
}
|
||||
|
||||
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) {
|
||||
if (m_bRenderingSnapshot)
|
||||
return false;
|
||||
|
|
@ -2729,3 +2810,7 @@ bool CHyprRenderer::shouldBlur(WP<Desktop::View::CPopup> p) {
|
|||
|
||||
return *PBLURPOPUPS && *PBLUR;
|
||||
}
|
||||
|
||||
bool CHyprRenderer::reloadShaders(const std::string& path) {
|
||||
return g_pHyprOpenGL->initShaders(path);
|
||||
}
|
||||
|
|
@ -1,7 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include "../defines.hpp"
|
||||
#include <hyprgraphics/color/Color.hpp>
|
||||
#include <hyprutils/math/Box.hpp>
|
||||
#include <list>
|
||||
#include <optional>
|
||||
#include "../helpers/Monitor.hpp"
|
||||
#include "../desktop/view/LayerSurface.hpp"
|
||||
#include "OpenGL.hpp"
|
||||
|
|
@ -10,12 +13,21 @@
|
|||
#include "../helpers/math/Math.hpp"
|
||||
#include "../helpers/time/Time.hpp"
|
||||
#include "../../protocols/cursor-shape-v1.hpp"
|
||||
#include "helpers/cm/ColorManagement.hpp"
|
||||
|
||||
struct SMonitorRule;
|
||||
class CWorkspace;
|
||||
class CInputPopup;
|
||||
class IHLBuffer;
|
||||
class CEventLoopTimer;
|
||||
|
||||
const std::vector<const char*> ASSET_PATHS = {
|
||||
#ifdef DATAROOTDIR
|
||||
DATAROOTDIR,
|
||||
#endif
|
||||
"/usr/share",
|
||||
"/usr/local/share",
|
||||
};
|
||||
class CToplevelExportProtocolManager;
|
||||
class CInputManager;
|
||||
struct SSessionLockSurface;
|
||||
|
|
@ -48,6 +60,29 @@ struct SRenderWorkspaceUntilData {
|
|||
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 {
|
||||
public:
|
||||
CHyprRenderer();
|
||||
|
|
@ -89,6 +124,9 @@ class CHyprRenderer {
|
|||
void renderSnapshot(PHLLS);
|
||||
void renderSnapshot(WP<Desktop::View::CPopup>);
|
||||
|
||||
//
|
||||
NColorManagement::PImageDescription workBufferImageDescription();
|
||||
|
||||
// if RENDER_MODE_NORMAL, provided damage will be written to.
|
||||
// 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);
|
||||
|
|
@ -121,6 +159,10 @@ class CHyprRenderer {
|
|||
|
||||
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:
|
||||
void arrangeLayerArray(PHLMONITOR, const std::vector<PHLLSREF>&, bool, CBox*);
|
||||
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_BRIGHTNESS] = getUniform("sdrBrightnessMultiplier");
|
||||
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_SIZE] = getUniform("iccLutSize");
|
||||
//
|
||||
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_POS_ATTRIB] = getAttrib("pos");
|
||||
m_uniformLocations[SHADER_TEX_ATTRIB] = getAttrib("texcoord");
|
||||
|
|
|
|||
|
|
@ -74,9 +74,11 @@ enum eShaderUniform : uint8_t {
|
|||
SHADER_POINTER_INACTIVE_TIMEOUT,
|
||||
SHADER_POINTER_LAST_ACTIVE,
|
||||
SHADER_POINTER_SIZE,
|
||||
SHADER_USE_ICC,
|
||||
SHADER_LUT_3D,
|
||||
SHADER_LUT_SIZE,
|
||||
SHADER_BLURRED_BG,
|
||||
SHADER_UV_SIZE,
|
||||
SHADER_UV_OFFSET,
|
||||
|
||||
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 @@
|
|||
uniform vec2 srcTFRange;
|
||||
uniform vec2 dstTFRange;
|
||||
#ifndef ALLOW_INCLUDES
|
||||
#define ALLOW_INCLUDES
|
||||
#extension GL_ARB_shading_language_include : enable
|
||||
#endif
|
||||
#include "cm_helpers.glsl"
|
||||
|
||||
uniform vec2 srcTFRange;
|
||||
uniform vec2 dstTFRange;
|
||||
|
||||
uniform float srcRefLuminance;
|
||||
uniform mat3 convertMatrix;
|
||||
uniform mat3 convertMatrix;
|
||||
|
||||
#include "sdr_mod.glsl"
|
||||
|
||||
uniform int useIcc;
|
||||
#if USE_ICC
|
||||
uniform highp sampler3D iccLut3D;
|
||||
uniform float iccLutSize;
|
||||
uniform float iccLutSize;
|
||||
#endif
|
||||
|
||||
//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
|
||||
#if USE_SDR_MOD
|
||||
uniform float sdrSaturation;
|
||||
uniform float sdrBrightnessMultiplier;
|
||||
#endif
|
||||
|
||||
// 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
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
#if USE_TONEMAP
|
||||
uniform float maxLuminance;
|
||||
uniform float dstMaxLuminance;
|
||||
uniform float dstRefLuminance;
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -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,143 +1,21 @@
|
|||
#version 300 es
|
||||
precision highp float;
|
||||
uniform sampler2D tex;
|
||||
#define ALLOW_INCLUDES
|
||||
#extension GL_ARB_shading_language_include : enable
|
||||
|
||||
uniform float radius;
|
||||
uniform vec2 halfpixel;
|
||||
uniform int passes;
|
||||
uniform float vibrancy;
|
||||
uniform float vibrancy_darkness;
|
||||
precision highp float;
|
||||
uniform sampler2D tex;
|
||||
|
||||
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;
|
||||
}
|
||||
uniform float radius;
|
||||
uniform vec2 halfpixel;
|
||||
uniform int passes;
|
||||
uniform float vibrancy;
|
||||
uniform float vibrancy_darkness;
|
||||
|
||||
in vec2 v_texcoord;
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
#include "blur1.glsl"
|
||||
|
||||
void main() {
|
||||
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) {
|
||||
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]);
|
||||
}
|
||||
fragColor = blur1(v_texcoord, tex, radius, halfpixel, passes, vibrancy, vibrancy_darkness);
|
||||
}
|
||||
|
|
|
|||
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,25 +1,18 @@
|
|||
#version 300 es
|
||||
precision highp float;
|
||||
#define ALLOW_INCLUDES
|
||||
#extension GL_ARB_shading_language_include : enable
|
||||
|
||||
precision highp float;
|
||||
|
||||
uniform sampler2D tex;
|
||||
uniform float radius;
|
||||
uniform vec2 halfpixel;
|
||||
uniform float radius;
|
||||
uniform vec2 halfpixel;
|
||||
|
||||
in vec2 v_texcoord;
|
||||
in vec2 v_texcoord;
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
#include "blur2.glsl"
|
||||
|
||||
void main() {
|
||||
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;
|
||||
|
||||
fragColor = sum / 12.0;
|
||||
fragColor = blur2(v_texcoord, tex, radius, halfpixel);
|
||||
}
|
||||
|
|
|
|||
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,30 +1,19 @@
|
|||
#version 300 es
|
||||
#define ALLOW_INCLUDES
|
||||
#extension GL_ARB_shading_language_include : enable
|
||||
|
||||
precision highp float;
|
||||
in vec2 v_texcoord; // is in 0-1
|
||||
precision highp float;
|
||||
in vec2 v_texcoord; // is in 0-1
|
||||
uniform sampler2D tex;
|
||||
|
||||
uniform float noise;
|
||||
uniform float brightness;
|
||||
uniform float noise;
|
||||
uniform float brightness;
|
||||
|
||||
float hash(vec2 p) {
|
||||
vec3 p3 = fract(vec3(p.xyx) * 1689.1984);
|
||||
p3 += dot(p3, p3.yzx + 33.33);
|
||||
return fract((p3.x + p3.y) * p3.z);
|
||||
}
|
||||
#include "blurFinish.glsl"
|
||||
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
void main() {
|
||||
vec4 pixColor = texture(tex, v_texcoord);
|
||||
|
||||
// noise
|
||||
float noiseHash = hash(v_texcoord);
|
||||
float noiseAmount = noiseHash - 0.5;
|
||||
pixColor.rgb += noiseAmount * noise;
|
||||
|
||||
// brightness
|
||||
pixColor.rgb *= min(1.0, brightness);
|
||||
|
||||
fragColor = pixColor;
|
||||
fragColor = blurFinish(pixColor, v_texcoord, noise, brightness);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,26 +1,38 @@
|
|||
#version 300 es
|
||||
#define ALLOW_INCLUDES
|
||||
#extension GL_ARB_shading_language_include : enable
|
||||
|
||||
precision highp float;
|
||||
in vec2 v_texcoord; // is in 0-1
|
||||
#include "defines.h"
|
||||
|
||||
precision highp float;
|
||||
in vec2 v_texcoord; // is in 0-1
|
||||
uniform sampler2D tex;
|
||||
|
||||
uniform float contrast;
|
||||
uniform float brightness;
|
||||
uniform float contrast;
|
||||
uniform float brightness;
|
||||
|
||||
#include "CM.glsl"
|
||||
#include "gain.glsl"
|
||||
uniform int sourceTF; // eTransferFunction
|
||||
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;
|
||||
void main() {
|
||||
vec4 pixColor = texture(tex, v_texcoord);
|
||||
|
||||
// contrast
|
||||
if (contrast != 1.0)
|
||||
pixColor.rgb = gain(pixColor.rgb, contrast);
|
||||
|
||||
// brightness
|
||||
pixColor.rgb *= max(1.0, brightness);
|
||||
|
||||
fragColor = pixColor;
|
||||
fragColor = fragColor = blurPrepare(texture(tex, v_texcoord), contrast, brightness
|
||||
#if USE_CM
|
||||
,
|
||||
sourceTF, targetTF, convertMatrix, srcTFRange, dstTFRange, srcRefLuminance, sdrBrightnessMultiplier
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
|
|
|||
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,92 +1,60 @@
|
|||
#version 300 es
|
||||
#define ALLOW_INCLUDES
|
||||
#extension GL_ARB_shading_language_include : enable
|
||||
|
||||
precision highp float;
|
||||
in vec2 v_texcoord;
|
||||
precision highp float;
|
||||
in vec2 v_texcoord;
|
||||
|
||||
uniform vec2 fullSizeUntransformed;
|
||||
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 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;
|
||||
|
||||
uniform float radius;
|
||||
uniform float roundingPower;
|
||||
uniform vec2 topLeft;
|
||||
uniform vec2 fullSize;
|
||||
#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 *= alpha * additionalAlpha;
|
||||
|
||||
fragColor = pixColor;
|
||||
fragColor = getBorder(v_texcoord, alpha, fullSizeUntransformed, radiusOuter, thick, radius, roundingPower, topLeft, fullSize, gradientLength, gradient, angle, gradient2Length,
|
||||
gradient2, angle2, gradientLerp
|
||||
#if USE_CM
|
||||
,
|
||||
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
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
float l = pow(lab[0] + lab[1] * 0.3963377774 + lab[2] * 0.2158037573, 3.0);
|
||||
float m = pow(lab[0] + lab[1] * (-0.1055613458) + lab[2] * (-0.0638541728), 3.0);
|
||||
float s = pow(lab[0] + lab[1] * (-0.0894841775) + lab[2] * (-1.2914855480), 3.0);
|
||||
|
||||
return vec4(fromLinearRGB(
|
||||
vec3(
|
||||
l * 4.0767416621 + m * -3.3077115913 + s * 0.2309699292,
|
||||
l * (-1.2684380046) + m * 2.6097574011 + s * (-0.3413193965),
|
||||
l * (-0.0041960863) + m * (-0.7034186147) + s * 1.7076147010
|
||||
), CM_TRANSFER_FUNCTION_GAMMA22
|
||||
), lab[3]);
|
||||
return vec4(fromLinearRGB(vec3(l * 4.0767416621 + m * -3.3077115913 + s * 0.2309699292, l * (-1.2684380046) + m * 2.6097574011 + s * (-0.3413193965),
|
||||
l * (-0.0041960863) + m * (-0.7034186147) + s * 1.7076147010),
|
||||
CM_TRANSFER_FUNCTION_GAMMA22),
|
||||
lab[3]);
|
||||
}
|
||||
|
||||
vec4 getOkColorForCoordArray1(vec2 normalizedCoord) {
|
||||
vec4 getOkColorForCoordArray1(vec2 normalizedCoord, int gradientLength, vec4 gradient[10], float angle) {
|
||||
if (gradientLength < 2)
|
||||
return gradient[0];
|
||||
|
||||
|
|
@ -20,14 +26,14 @@ vec4 getOkColorForCoordArray1(vec2 normalizedCoord) {
|
|||
|
||||
if (angle > 4.71 /* 270 deg */) {
|
||||
normalizedCoord[1] = 1.0 - normalizedCoord[1];
|
||||
finalAng = 6.28 - angle;
|
||||
finalAng = 6.28 - angle;
|
||||
} else if (angle > 3.14 /* 180 deg */) {
|
||||
normalizedCoord[0] = 1.0 - normalizedCoord[0];
|
||||
normalizedCoord[1] = 1.0 - normalizedCoord[1];
|
||||
finalAng = angle - 3.14;
|
||||
finalAng = angle - 3.14;
|
||||
} else if (angle > 1.57 /* 90 deg */) {
|
||||
normalizedCoord[0] = 1.0 - normalizedCoord[0];
|
||||
finalAng = 3.14 - angle;
|
||||
finalAng = 3.14 - angle;
|
||||
} else {
|
||||
finalAng = angle;
|
||||
}
|
||||
|
|
@ -35,13 +41,13 @@ vec4 getOkColorForCoordArray1(vec2 normalizedCoord) {
|
|||
float sine = sin(finalAng);
|
||||
|
||||
float progress = (normalizedCoord[1] * sine + normalizedCoord[0] * (1.0 - sine)) * float(gradientLength - 1);
|
||||
int bottom = int(floor(progress));
|
||||
int top = bottom + 1;
|
||||
int bottom = int(floor(progress));
|
||||
int top = bottom + 1;
|
||||
|
||||
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)
|
||||
return gradient2[0];
|
||||
|
||||
|
|
@ -49,14 +55,14 @@ vec4 getOkColorForCoordArray2(vec2 normalizedCoord) {
|
|||
|
||||
if (angle2 > 4.71 /* 270 deg */) {
|
||||
normalizedCoord[1] = 1.0 - normalizedCoord[1];
|
||||
finalAng = 6.28 - angle;
|
||||
finalAng = 6.28 - angle;
|
||||
} else if (angle2 > 3.14 /* 180 deg */) {
|
||||
normalizedCoord[0] = 1.0 - normalizedCoord[0];
|
||||
normalizedCoord[1] = 1.0 - normalizedCoord[1];
|
||||
finalAng = angle - 3.14;
|
||||
finalAng = angle - 3.14;
|
||||
} else if (angle2 > 1.57 /* 90 deg */) {
|
||||
normalizedCoord[0] = 1.0 - normalizedCoord[0];
|
||||
finalAng = 3.14 - angle2;
|
||||
finalAng = 3.14 - angle2;
|
||||
} else {
|
||||
finalAng = angle2;
|
||||
}
|
||||
|
|
@ -64,19 +70,134 @@ vec4 getOkColorForCoordArray2(vec2 normalizedCoord) {
|
|||
float sine = sin(finalAng);
|
||||
|
||||
float progress = (normalizedCoord[1] * sine + normalizedCoord[0] * (1.0 - sine)) * float(gradient2Length - 1);
|
||||
int bottom = int(floor(progress));
|
||||
int top = bottom + 1;
|
||||
int bottom = int(floor(progress));
|
||||
int top = bottom + 1;
|
||||
|
||||
return gradient2[top] * (progress - float(bottom)) + gradient2[bottom] * (float(top) - progress);
|
||||
}
|
||||
|
||||
vec4 getColorForCoord(vec2 normalizedCoord) {
|
||||
vec4 result1 = getOkColorForCoordArray1(normalizedCoord);
|
||||
vec4 getColorForCoord(vec2 normalizedCoord, int gradientLength, vec4 gradient[10], float angle, int gradient2Length, vec4 gradient2[10], float angle2, float gradientLerp) {
|
||||
vec4 result1 = getOkColorForCoordArray1(normalizedCoord, gradientLength, gradient, angle);
|
||||
|
||||
if (gradient2Length <= 0)
|
||||
return okLabAToSrgb(result1);
|
||||
|
||||
vec4 result2 = getOkColorForCoordArray2(normalizedCoord);
|
||||
vec4 result2 = getOkColorForCoordArray2(normalizedCoord, angle, gradient2Length, gradient2, angle2);
|
||||
|
||||
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,20 +1,25 @@
|
|||
#version 300 es
|
||||
|
||||
#define ALLOW_INCLUDES
|
||||
#extension GL_ARB_shading_language_include : enable
|
||||
#extension GL_OES_EGL_image_external_essl3 : require
|
||||
|
||||
precision highp float;
|
||||
in vec2 v_texcoord;
|
||||
precision highp float;
|
||||
in vec2 v_texcoord;
|
||||
uniform samplerExternalOES tex;
|
||||
uniform float alpha;
|
||||
uniform float alpha;
|
||||
|
||||
uniform float radius;
|
||||
uniform float roundingPower;
|
||||
uniform vec2 topLeft;
|
||||
uniform vec2 fullSize;
|
||||
#include "rounding.glsl"
|
||||
|
||||
uniform int discardOpaque;
|
||||
uniform int discardAlpha;
|
||||
uniform int discardAlphaValue;
|
||||
uniform int discardOpaque;
|
||||
uniform int discardAlpha;
|
||||
uniform int discardAlphaValue;
|
||||
|
||||
uniform int applyTint;
|
||||
uniform int applyTint;
|
||||
uniform vec3 tint;
|
||||
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
|
@ -23,16 +28,16 @@ void main() {
|
|||
vec4 pixColor = texture(tex, v_texcoord);
|
||||
|
||||
if (discardOpaque == 1 && pixColor[3] * alpha == 1.0)
|
||||
discard;
|
||||
discard;
|
||||
|
||||
if (applyTint == 1) {
|
||||
pixColor[0] = pixColor[0] * tint[0];
|
||||
pixColor[1] = pixColor[1] * tint[1];
|
||||
pixColor[2] = pixColor[2] * tint[2];
|
||||
pixColor[0] = pixColor[0] * tint[0];
|
||||
pixColor[1] = pixColor[1] * tint[1];
|
||||
pixColor[2] = pixColor[2] * tint[2];
|
||||
}
|
||||
|
||||
if (radius > 0.0)
|
||||
pixColor = rounding(pixColor);
|
||||
pixColor = rounding(pixColor, radius, roundingPower, topLeft, fullSize);
|
||||
|
||||
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
|
||||
|
||||
#define ALLOW_INCLUDES
|
||||
#extension GL_ARB_shading_language_include : enable
|
||||
precision highp float;
|
||||
in vec4 v_color;
|
||||
#include "defines.h"
|
||||
|
||||
precision highp float;
|
||||
in vec4 v_color;
|
||||
|
||||
#if USE_ROUNDING
|
||||
uniform float radius;
|
||||
uniform float roundingPower;
|
||||
uniform vec2 topLeft;
|
||||
uniform vec2 fullSize;
|
||||
#include "rounding.glsl"
|
||||
#endif
|
||||
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
void main() {
|
||||
vec4 pixColor = v_color;
|
||||
|
||||
if (radius > 0.0)
|
||||
pixColor = rounding(pixColor);
|
||||
#if USE_ROUNDING
|
||||
pixColor = rounding(pixColor, radius, roundingPower, topLeft, fullSize);
|
||||
#endif
|
||||
|
||||
fragColor = pixColor;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,10 @@
|
|||
#ifndef ROUNDING_GLSL
|
||||
#define ROUNDING_GLSL
|
||||
// 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)
|
||||
|
||||
uniform float radius;
|
||||
uniform float roundingPower;
|
||||
uniform vec2 topLeft;
|
||||
uniform vec2 fullSize;
|
||||
|
||||
vec4 rounding(vec4 color) {
|
||||
vec4 rounding(vec4 color, float radius, float roundingPower, vec2 topLeft, vec2 fullSize) {
|
||||
vec2 pixCoord = vec2(gl_FragCoord);
|
||||
pixCoord -= topLeft + fullSize * 0.5;
|
||||
pixCoord *= vec2(lessThan(pixCoord, vec2(0.0))) * -2.0 + 1.0;
|
||||
|
|
@ -15,7 +12,7 @@ vec4 rounding(vec4 color) {
|
|||
pixCoord += vec2(1.0, 1.0) / fullSize; // center the pix don't make it top-left
|
||||
|
||||
if (pixCoord.x + pixCoord.y > radius) {
|
||||
float dist = pow(pow(pixCoord.x, roundingPower) + pow(pixCoord.y, roundingPower), 1.0/roundingPower);
|
||||
float dist = pow(pow(pixCoord.x, roundingPower) + pow(pixCoord.y, roundingPower), 1.0 / roundingPower);
|
||||
|
||||
if (dist > radius + SMOOTHING_CONSTANT)
|
||||
discard;
|
||||
|
|
@ -27,3 +24,4 @@ vec4 rounding(vec4 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,93 +1,57 @@
|
|||
#version 300 es
|
||||
#define ALLOW_INCLUDES
|
||||
#extension GL_ARB_shading_language_include : enable
|
||||
|
||||
precision highp float;
|
||||
in vec4 v_color;
|
||||
in vec2 v_texcoord;
|
||||
#include "defines.h"
|
||||
|
||||
uniform int sourceTF; // eTransferFunction
|
||||
uniform int targetTF; // eTransferFunction
|
||||
uniform mat3 targetPrimariesXYZ;
|
||||
precision highp float;
|
||||
in vec4 v_color;
|
||||
in vec2 v_texcoord;
|
||||
|
||||
uniform vec2 topLeft;
|
||||
uniform vec2 bottomRight;
|
||||
uniform vec2 fullSize;
|
||||
uniform int sourceTF; // eTransferFunction
|
||||
uniform int targetTF; // eTransferFunction
|
||||
uniform mat3 targetPrimariesXYZ;
|
||||
|
||||
uniform vec2 topLeft;
|
||||
uniform vec2 bottomRight;
|
||||
uniform vec2 fullSize;
|
||||
uniform float radius;
|
||||
uniform float roundingPower;
|
||||
uniform float range;
|
||||
uniform float shadowPower;
|
||||
|
||||
float pixAlphaRoundedDistance(float distanceToCorner) {
|
||||
if (distanceToCorner > radius) {
|
||||
return 0.0;
|
||||
}
|
||||
#if USE_CM
|
||||
#include "cm_helpers.glsl"
|
||||
#include "CM.glsl"
|
||||
#endif
|
||||
|
||||
if (distanceToCorner > radius - range) {
|
||||
return pow((range - (distanceToCorner - radius + range)) / range, shadowPower); // i think?
|
||||
}
|
||||
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
float modifiedLength(vec2 a) {
|
||||
return pow(pow(abs(a.x),roundingPower)+pow(abs(a.y),roundingPower),1.0/roundingPower);
|
||||
}
|
||||
#include "shadow.glsl"
|
||||
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
void main() {
|
||||
vec4 pixColor = v_color;
|
||||
|
||||
vec4 pixColor = v_color;
|
||||
float originalAlpha = pixColor[3];
|
||||
|
||||
bool done = false;
|
||||
|
||||
vec2 pixCoord = fullSize * v_texcoord;
|
||||
|
||||
// ok, now we check the distance to a border.
|
||||
|
||||
if (pixCoord[0] < topLeft[0]) {
|
||||
if (pixCoord[1] < topLeft[1]) {
|
||||
// top left
|
||||
pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(modifiedLength(pixCoord - topLeft));
|
||||
done = true;
|
||||
} else if (pixCoord[1] > bottomRight[1]) {
|
||||
// bottom left
|
||||
pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(modifiedLength(pixCoord - vec2(topLeft[0], bottomRight[1])));
|
||||
done = true;
|
||||
}
|
||||
} else if (pixCoord[0] > bottomRight[0]) {
|
||||
if (pixCoord[1] < topLeft[1]) {
|
||||
// top right
|
||||
pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(modifiedLength(pixCoord - vec2(bottomRight[0], topLeft[1])));
|
||||
done = true;
|
||||
} else if (pixCoord[1] > bottomRight[1]) {
|
||||
// bottom right
|
||||
pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(modifiedLength(pixCoord - bottomRight));
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!done) {
|
||||
// distance to all straight bb borders
|
||||
float distanceT = pixCoord[1];
|
||||
float distanceB = fullSize[1] - pixCoord[1];
|
||||
float distanceL = pixCoord[0];
|
||||
float distanceR = fullSize[0] - pixCoord[0];
|
||||
|
||||
// get the smallest
|
||||
float smallest = min(min(distanceT, distanceB), min(distanceL, distanceR));
|
||||
|
||||
if (smallest < range) {
|
||||
pixColor[3] = pixColor[3] * pow((smallest / range), shadowPower);
|
||||
}
|
||||
}
|
||||
|
||||
if (pixColor[3] == 0.0) {
|
||||
discard; return;
|
||||
}
|
||||
|
||||
// premultiply
|
||||
pixColor.rgb *= pixColor[3];
|
||||
|
||||
fragColor = pixColor;
|
||||
fragColor = getShadow(pixColor, v_texcoord, radius, roundingPower, topLeft, fullSize, range, shadowPower, bottomRight
|
||||
#if USE_CM
|
||||
,
|
||||
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
|
||||
);
|
||||
}
|
||||
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
|
||||
#define ALLOW_INCLUDES
|
||||
#extension GL_ARB_shading_language_include : enable
|
||||
|
||||
precision highp float;
|
||||
in vec2 v_texcoord;
|
||||
#include "defines.h"
|
||||
|
||||
precision highp float;
|
||||
in vec2 v_texcoord;
|
||||
uniform sampler2D tex;
|
||||
#if USE_BLUR
|
||||
uniform vec2 uvSize;
|
||||
uniform vec2 uvOffset;
|
||||
uniform sampler2D blurredBG;
|
||||
#endif
|
||||
|
||||
uniform float alpha;
|
||||
|
||||
#include "discard.glsl"
|
||||
#include "tint.glsl"
|
||||
#if USE_DISCARD
|
||||
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 "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;
|
||||
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"
|
||||
#include "do_CM.glsl"
|
||||
#include "do_tint.glsl"
|
||||
#include "do_rounding.glsl"
|
||||
#if USE_DISCARD && !USE_BLUR
|
||||
if (discardOpaque && pixColor.a * alpha == 1.0)
|
||||
discard;
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
uniform float dstMaxLuminance;
|
||||
uniform float dstRefLuminance;
|
||||
#ifndef ALLOW_INCLUDES
|
||||
#define ALLOW_INCLUDES
|
||||
#extension GL_ARB_shading_language_include : enable
|
||||
#endif
|
||||
#include "constants.h"
|
||||
|
||||
const mat3 BT2020toLMS = mat3(
|
||||
0.3592, 0.6976, -0.0358,
|
||||
-0.1922, 1.1004, 0.0755,
|
||||
0.0070, 0.0749, 0.8434
|
||||
);
|
||||
const mat3 BT2020toLMS = mat3(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 = mat3(
|
||||
2.0701800566956135096, -1.3264568761030210255, 0.20661600684785517081,
|
||||
0.36498825003265747974, 0.68046736285223514102, -0.045421753075853231409,
|
||||
-0.049595542238932107896, -0.049421161186757487412, 1.1879959417328034394
|
||||
const mat3 LMStoBT2020 = mat3( //
|
||||
2.0701800566956135096, -1.3264568761030210255, 0.20661600684785517081, //
|
||||
0.36498825003265747974, 0.68046736285223514102, -0.045421753075853231409, //
|
||||
-0.049595542238932107896, -0.049421161186757487412, 1.1879959417328034394 //
|
||||
);
|
||||
|
||||
// const mat3 ICtCpPQ = transpose(mat3(
|
||||
|
|
@ -19,16 +17,16 @@ const mat3 LMStoBT2020 = mat3(
|
|||
// 6610.0, -13613.0, 7003.0,
|
||||
// 17933.0, -17390.0, -543.0
|
||||
// ) / 4096.0);
|
||||
const mat3 ICtCpPQ = mat3(
|
||||
0.5, 1.61376953125, 4.378173828125,
|
||||
0.5, -3.323486328125, -4.24560546875,
|
||||
0.0, 1.709716796875, -0.132568359375
|
||||
const mat3 ICtCpPQ = mat3( //
|
||||
0.5, 1.61376953125, 4.378173828125, //
|
||||
0.5, -3.323486328125, -4.24560546875, //
|
||||
0.0, 1.709716796875, -0.132568359375 //
|
||||
);
|
||||
//const mat3 ICtCpPQInv = inverse(ICtCpPQ);
|
||||
const mat3 ICtCpPQInv = mat3(
|
||||
1.0, 1.0, 1.0,
|
||||
0.0086090370379327566, -0.0086090370379327566, 0.560031335710679118,
|
||||
0.11102962500302595656, -0.11102962500302595656, -0.32062717498731885185
|
||||
const mat3 ICtCpPQInv = mat3( //
|
||||
1.0, 1.0, 1.0, //
|
||||
0.0086090370379327566, -0.0086090370379327566, 0.560031335710679118, //
|
||||
0.11102962500302595656, -0.11102962500302595656, -0.32062717498731885185 //
|
||||
);
|
||||
|
||||
// unused for now
|
||||
|
|
@ -39,31 +37,28 @@ const mat3 ICtCpPQInv = mat3(
|
|||
// ) / 4096.0);
|
||||
// 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)
|
||||
return vec4(clamp(color.rgb, vec3(0.0), vec3(dstMaxLuminance)), color[3]);
|
||||
|
||||
mat3 toLMS = BT2020toLMS * dstXYZ;
|
||||
mat3 fromLMS = inverse(dstXYZ) * LMStoBT2020;
|
||||
mat3 toLMS = BT2020toLMS * dstXYZ;
|
||||
mat3 fromLMS = inverse(dstXYZ) * LMStoBT2020;
|
||||
|
||||
vec3 lms = fromLinear(vec4((toLMS * color.rgb) / HDR_MAX_LUMINANCE, 1.0), CM_TRANSFER_FUNCTION_ST2084_PQ).rgb;
|
||||
vec3 ICtCp = ICtCpPQ * lms;
|
||||
vec3 lms = fromLinear(vec4((toLMS * color.rgb) / HDR_MAX_LUMINANCE, 1.0), CM_TRANSFER_FUNCTION_ST2084_PQ).rgb;
|
||||
vec3 ICtCp = ICtCpPQ * lms;
|
||||
|
||||
float E = pow(clamp(ICtCp[0], 0.0, 1.0), PQ_INV_M2);
|
||||
float luminance = pow(
|
||||
(max(E - PQ_C1, 0.0)) / (PQ_C2 - PQ_C3 * E),
|
||||
PQ_INV_M1
|
||||
) * HDR_MAX_LUMINANCE;
|
||||
float E = pow(clamp(ICtCp[0], 0.0, 1.0), PQ_INV_M2);
|
||||
float luminance = pow((max(E - PQ_C1, 0.0)) / (PQ_C2 - PQ_C3 * E), PQ_INV_M1) * HDR_MAX_LUMINANCE;
|
||||
|
||||
float linearPart = min(luminance, dstRefLuminance);
|
||||
float luminanceAboveRef = max(luminance - dstRefLuminance, 0.0);
|
||||
float linearPart = min(luminance, dstRefLuminance);
|
||||
float luminanceAboveRef = max(luminance - dstRefLuminance, 0.0);
|
||||
float maxExcessLuminance = max(maxLuminance - dstRefLuminance, 1.0);
|
||||
float shoulder = log((luminanceAboveRef / maxExcessLuminance + 1.0) * (M_E - 1.0));
|
||||
float mappedHigh = shoulder * (dstMaxLuminance - dstRefLuminance);
|
||||
float newLum = clamp(linearPart + mappedHigh, 0.0, dstMaxLuminance);
|
||||
float shoulder = log((luminanceAboveRef / maxExcessLuminance + 1.0) * (M_E - 1.0));
|
||||
float mappedHigh = shoulder * (dstMaxLuminance - dstRefLuminance);
|
||||
float newLum = clamp(linearPart + mappedHigh, 0.0, dstMaxLuminance);
|
||||
|
||||
// scale src to dst reference
|
||||
float refScale = dstRefLuminance / srcRefLuminance;
|
||||
|
||||
return vec4(fromLMS * toLinear(vec4(ICtCpPQInv * ICtCp, 1.0), CM_TRANSFER_FUNCTION_ST2084_PQ).rgb * HDR_MAX_LUMINANCE * refScale, color[3]);
|
||||
return vec4(fromLMS * toLinear(vec4(ICtCpPQInv * ICtCp, 1.0), CM_TRANSFER_FUNCTION_ST2084_PQ).rgb * HDR_MAX_LUMINANCE * refScale, color[3]);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue