diff options
Diffstat (limited to 'src/multimedia/shaders')
28 files changed, 780 insertions, 0 deletions
diff --git a/src/multimedia/shaders/abgr.frag b/src/multimedia/shaders/abgr.frag new file mode 100644 index 000000000..7eadb092d --- /dev/null +++ b/src/multimedia/shaders/abgr.frag @@ -0,0 +1,19 @@ +#version 440 +#extension GL_GOOGLE_include_directive : enable + +#include "uniformbuffer.glsl" +#include "colortransfer.glsl" + +layout(location = 0) in vec2 texCoord; +layout(location = 0) out vec4 fragColor; + +layout(binding = 1) uniform sampler2D rgbTexture; + +void main() +{ + fragColor = ubuf.colorMatrix * texture(rgbTexture, texCoord).abgr * ubuf.opacity; + +#ifdef QMM_OUTPUTSURFACE_LINEAR + fragColor = convertSRGBToLinear(fragColor); +#endif +} diff --git a/src/multimedia/shaders/argb.frag b/src/multimedia/shaders/argb.frag new file mode 100644 index 000000000..1adbc8dba --- /dev/null +++ b/src/multimedia/shaders/argb.frag @@ -0,0 +1,19 @@ +#version 440 +#extension GL_GOOGLE_include_directive : enable + +#include "uniformbuffer.glsl" +#include "colortransfer.glsl" + +layout(location = 0) in vec2 texCoord; +layout(location = 0) out vec4 fragColor; + +layout(binding = 1) uniform sampler2D rgbTexture; + +void main() +{ + fragColor = ubuf.colorMatrix * texture(rgbTexture, texCoord).gbar * ubuf.opacity; + +#ifdef QMM_OUTPUTSURFACE_LINEAR + fragColor = convertSRGBToLinear(fragColor); +#endif +} diff --git a/src/multimedia/shaders/ayuv.frag b/src/multimedia/shaders/ayuv.frag new file mode 100644 index 000000000..92c3f71fe --- /dev/null +++ b/src/multimedia/shaders/ayuv.frag @@ -0,0 +1,25 @@ +#version 440 +#extension GL_GOOGLE_include_directive : enable + +#include "uniformbuffer.glsl" +#include "colortransfer.glsl" + +layout(location = 0) in vec2 texCoord; +layout(location = 0) out vec4 fragColor; + +layout(binding = 1) uniform sampler2D plane1Texture; + +void main() +{ + vec3 YUV = texture(plane1Texture, texCoord).gba; + float A = texture(plane1Texture, texCoord).r; + fragColor = ubuf.colorMatrix * vec4(YUV, 1.0) * A * ubuf.opacity; + +#ifdef QMM_OUTPUTSURFACE_LINEAR + fragColor = convertSRGBToLinear(fragColor); +#endif + + // Clamp output to valid range to account for out-of-range + // input values and numerical inaccuracies in YUV->RGB conversion + fragColor = clamp(fragColor, 0.0, 1.0); +} diff --git a/src/multimedia/shaders/bgra.frag b/src/multimedia/shaders/bgra.frag new file mode 100644 index 000000000..0ba0e4c9e --- /dev/null +++ b/src/multimedia/shaders/bgra.frag @@ -0,0 +1,19 @@ +#version 440 +#extension GL_GOOGLE_include_directive : enable + +#include "uniformbuffer.glsl" +#include "colortransfer.glsl" + +layout(location = 0) in vec2 texCoord; +layout(location = 0) out vec4 fragColor; + +layout(binding = 1) uniform sampler2D rgbTexture; + +void main() +{ + fragColor = ubuf.colorMatrix * texture(rgbTexture, texCoord).bgra * ubuf.opacity; + +#ifdef QMM_OUTPUTSURFACE_LINEAR + fragColor = convertSRGBToLinear(fragColor); +#endif +} diff --git a/src/multimedia/shaders/colorconvert.glsl b/src/multimedia/shaders/colorconvert.glsl new file mode 100644 index 000000000..f28a0902e --- /dev/null +++ b/src/multimedia/shaders/colorconvert.glsl @@ -0,0 +1,19 @@ +#ifndef COLORCONVERT +#define COLORCONVERT + +// Convert the Rec2020 RGB colorspace to sRGB using: +// https://www.itu.int/dms_pub/itu-r/opb/rep/R-REP-BT.2407-2017-PDF-E.pdf +// We can use the simple matrix defined there for a conversion between BT2020 +// and sRGB. Conversion has to be done in linear color space. +vec4 convertRec2020ToSRGB(vec4 rgba) +{ + const mat4 mat = + mat4(1.6605f, -0.5876f, -0.0728f, 0.0000f, + -0.1246f, 1.1329f, -0.0083f, 0.0000f, + -0.0182f, -0.1006f, 1.1187f, 0.0000f, + 0.0000f, 0.0000f, 0.0000f, 1.0000f); + + return rgba * mat; +} + +#endif diff --git a/src/multimedia/shaders/colortransfer.glsl b/src/multimedia/shaders/colortransfer.glsl new file mode 100644 index 000000000..1d70ae9eb --- /dev/null +++ b/src/multimedia/shaders/colortransfer.glsl @@ -0,0 +1,118 @@ +#ifndef PERCEPTUAL_QUANTIZER +#define PERCEPTUAL_QUANTIZER + +// Convert Rec.709 to linear +vec4 convertRec709ToLinear(vec4 rgba) +{ + const vec4 alphaMinusOne = vec4(0.099, 0.099, 0.099, 0); + const vec4 alpha = alphaMinusOne + 1.; + bvec4 cutoff = lessThan(rgba, vec4(0.081)); + vec4 high = pow((rgba + alphaMinusOne)/alpha, vec4(1./0.45)); + vec4 low = rgba/4.5; + return mix(high, low, cutoff); +} + +vec4 convertSRGBToLinear(vec4 sRGB) +{ + // https://en.wikipedia.org/wiki/SRGB + const bvec3 cutoff = lessThanEqual(sRGB.rgb, vec3(0.04045)); + const vec3 low = sRGB.rgb / 12.92; + const vec3 high = pow((sRGB.rgb + 0.055) / 1.055, vec3(2.4)); + vec3 linear = mix(high, low, cutoff); + return vec4(linear, sRGB.a); +} + +vec4 convertSRGBFromLinear(vec4 linear) +{ + // https://en.wikipedia.org/wiki/SRGB + const bvec3 cutoff = lessThanEqual(linear.rgb, vec3(0.0031308)); + const vec3 low = linear.rgb * 12.92; + const vec3 high = 1.055 * pow(linear.rgb, vec3(1.0 / 2.4f)) - 0.055; + vec3 sRGB = mix(high, low, cutoff); + return vec4(sRGB, linear.a); +} + +// This uses the PQ transfer function, see also https://en.wikipedia.org/wiki/Perceptual_quantizer +// or https://ieeexplore.ieee.org/document/7291452 +const float SDR_LEVEL = 100.; + +vec4 convertPQToLinear(vec4 rgba) +{ + const vec4 one_over_m1 = vec4(8192./1305.); + const vec4 one_over_m2 = vec4(32./2523.); + const float c1 = 107./128.; + const float c2 = 2413./128; + const float c3 = 2392./128.; + + vec4 e = pow(rgba, one_over_m2); + vec4 num = max(e - c1, 0); + vec4 den = c2 - c3*e; + return pow(num/den, one_over_m1)*10000./SDR_LEVEL; +} + +vec4 convertPQFromLinear(vec4 rgba) +{ + const float m1 = float(1305./8192.); + const float m2 = float(2523./32.); + const float c1 = 107./128.; + const float c2 = 2413./128; + const float c3 = 2392./128.; + + rgba *= SDR_LEVEL/10000.; + vec4 p = pow(rgba, vec4(m1)); + vec4 num = c1 + c2*p; + vec4 den = 1. + c3*p; + return pow(num/den, vec4(m2)); +} + +float convertPQToLinear(float sig) +{ + const float one_over_m1 = float(8192./1305.); + const float one_over_m2 = float(32./2523.); + const float c1 = 107./128.; + const float c2 = 2413./128; + const float c3 = 2392./128.; + + float e = pow(sig, one_over_m2); + float num = max(e - c1, 0); + float den = c2 - c3*e; + return pow(num/den, one_over_m1)*10000./SDR_LEVEL; +} + +float convertPQFromLinear(float sig) +{ + const float m1 = float(1305./8192.); + const float m2 = float(2523./32.); + const float c1 = 107./128.; + const float c2 = 2413./128; + const float c3 = 2392./128.; + + sig *= SDR_LEVEL/10000.; + float p = pow(sig, m1); + float num = c1 + c2*p; + float den = 1. + c3*p; + return pow(num/den, m2); +} + +// This implements support for HLG transfer functions, see also https://en.wikipedia.org/wiki/Hybrid_log–gamma + + +vec4 convertHLGToLinear(vec4 rgba, float maxLum) +{ + const float a = 0.17883277; + const float b = 0.28466892; // = 1 - 4a + const float c = 0.55991073; // = 0.5 - a ln(4a) + + bvec4 cutoff = lessThan(rgba, vec4(0.5)); + vec4 low = rgba*rgba/3; + vec4 high = (exp((rgba - c)/a) + b)/12.; + rgba = mix(high, low, cutoff); + + float lum = dot(rgba, vec4(0.2627, 0.6780, 0.0593, 0.)); + float y = pow(lum, 0.2); // gamma-1 with gamma = 1.2 + + rgba *= y*maxLum; + return rgba; +} + +#endif diff --git a/src/multimedia/shaders/compile.bat b/src/multimedia/shaders/compile.bat new file mode 100755 index 000000000..8a012d265 --- /dev/null +++ b/src/multimedia/shaders/compile.bat @@ -0,0 +1,16 @@ +:: Copyright (C) 2019 The Qt Company Ltd. +:: SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +qsb -b --glsl "150,120,100 es" --hlsl 50 --msl 12 -o rgba.vert.qsb rgba.vert +qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o rgba.frag.qsb rgba.frag + +qsb -b --glsl "150,120,100 es" --hlsl 50 --msl 12 -o yuv.vert.qsb yuv.vert +qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o yuv_yv.frag.qsb yuv_yv.frag + +qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o nv12.frag.qsb nv12.frag +qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o nv21.frag.qsb nv21.frag +qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o uyvy.frag.qsb uyvy.frag +qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o yuyv.frag.qsb yuyv.frag +qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o ayuv.frag.qsb ayuv.frag +qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o p010be.frag.qsb p010be.frag +qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o p010be.frag.qsb p010be.frag diff --git a/src/multimedia/shaders/externalsampler.frag b/src/multimedia/shaders/externalsampler.frag new file mode 100644 index 000000000..f786bc4e1 --- /dev/null +++ b/src/multimedia/shaders/externalsampler.frag @@ -0,0 +1,14 @@ +#version 440 +#extension GL_GOOGLE_include_directive : enable + +#include "uniformbuffer.glsl" + +layout(location = 0) in vec2 texCoord; +layout(location = 0) out vec4 fragColor; + +layout(binding = 1) uniform sampler2D plane1Texture; + +void main() +{ + fragColor = vec4(1., 0., 0., 0.); +} diff --git a/src/multimedia/shaders/externalsampler.vert b/src/multimedia/shaders/externalsampler.vert new file mode 100644 index 000000000..e693370dc --- /dev/null +++ b/src/multimedia/shaders/externalsampler.vert @@ -0,0 +1,16 @@ +#version 440 +#extension GL_GOOGLE_include_directive : enable + +#include "uniformbuffer.glsl" + +layout(location = 0) in vec4 vertexPosition; +layout(location = 1) in vec2 vertexTexCoord; + +layout(location = 0) out vec2 texCoord; + +out gl_PerVertex { vec4 gl_Position; }; + +void main() { + texCoord = (ubuf.colorMatrix * vec4(vertexTexCoord, 0.0, 1.0)).xy; + gl_Position = ubuf.matrix * vertexPosition; +} diff --git a/src/multimedia/shaders/externalsampler_gles.frag b/src/multimedia/shaders/externalsampler_gles.frag new file mode 100644 index 000000000..1292acebc --- /dev/null +++ b/src/multimedia/shaders/externalsampler_gles.frag @@ -0,0 +1,28 @@ +#extension GL_OES_EGL_image_external : require +precision highp float; +precision highp int; + +struct buf +{ + mat4 matrix; + mat4 colorMatrix; + float opacity; + float width; + float masteringWhite; + float maxLum; +}; + +uniform buf ubuf; + +uniform samplerExternalOES plane1Texture; + +varying vec2 texCoord; + +void main() +{ + gl_FragColor = texture2D(plane1Texture, texCoord).rgba * ubuf.opacity; + +#ifdef QMM_OUTPUTSURFACE_LINEAR + fragColor = pow(fragColor, 2.2); +#endif +} diff --git a/src/multimedia/shaders/hdrtonemapper.glsl b/src/multimedia/shaders/hdrtonemapper.glsl new file mode 100644 index 000000000..e10b6eca3 --- /dev/null +++ b/src/multimedia/shaders/hdrtonemapper.glsl @@ -0,0 +1,38 @@ +#ifndef HDR_TONEMAPPER +#define HDR_TONEMAPPER + +#include "colortransfer.glsl" + +// See https://www.itu.int/dms_pub/itu-r/opb/rep/R-REP-BT.2390-6-2019-PDF-E.pdf, section 5.4 +// +// masteringWhite in PQ values, not in linear. maxOutLum as defined in the doc above +// we assume that masteringBlack == 0, and minLum == 0 to simplify the calculations +// +// The HDR tonemapping operates in non linear space (PQ or HLG), taking the +// non linear luminosity as input and returning a factor by which to scale +// the RGB signal so it fits within the outbut devices range. +// +// We're using the same algorithm for HLG, and do the equivalent mapping in +// HLG space. +float tonemapScaleForLuminosity(float y, float masteringWhite, float maxLum) +{ + float p = y/masteringWhite; + + float ks = 1.5*maxLum - 0.5; + + if (p < ks) + return 1.; + + float t = (p - ks)/(1 - ks); + float t2 = t*t; + float t3 = t*t2; + + p = (2*t3 - 3*t2 + 1)*ks + (t3 - 2*t2 + t)*(1. - ks) + (-2*t3 + 3*t2)*maxLum; + + // get the linear new luminosity + float newY = p*masteringWhite; + + return newY/y; +} + +#endif diff --git a/src/multimedia/shaders/imc2.frag b/src/multimedia/shaders/imc2.frag new file mode 100644 index 000000000..18401d420 --- /dev/null +++ b/src/multimedia/shaders/imc2.frag @@ -0,0 +1,29 @@ +#version 440 +#extension GL_GOOGLE_include_directive : enable + +#include "uniformbuffer.glsl" +#include "colortransfer.glsl" + +layout(location = 0) in vec2 texCoord; +layout(location = 0) out vec4 fragColor; + +layout(binding = 1) uniform sampler2D plane1Texture; +layout(binding = 2) uniform sampler2D plane2Texture; + +void main() +{ + float Y = texture(plane1Texture, texCoord).r; + float x = texCoord.x/2.; + float U = texture(plane2Texture, vec2(x + .5, texCoord.y)).r; + float V = texture(plane2Texture, vec2(x, texCoord.y)).r; + vec4 color = vec4(Y, U, V, 1.); + fragColor = ubuf.colorMatrix * color * ubuf.opacity; + +#ifdef QMM_OUTPUTSURFACE_LINEAR + fragColor = convertSRGBToLinear(fragColor); +#endif + + // Clamp output to valid range to account for out-of-range + // input values and numerical inaccuracies in YUV->RGB conversion + fragColor = clamp(fragColor, 0.0, 1.0); +} diff --git a/src/multimedia/shaders/imc4.frag b/src/multimedia/shaders/imc4.frag new file mode 100644 index 000000000..574a5f49b --- /dev/null +++ b/src/multimedia/shaders/imc4.frag @@ -0,0 +1,29 @@ +#version 440 +#extension GL_GOOGLE_include_directive : enable + +#include "uniformbuffer.glsl" +#include "colortransfer.glsl" + +layout(location = 0) in vec2 texCoord; +layout(location = 0) out vec4 fragColor; + +layout(binding = 1) uniform sampler2D plane1Texture; +layout(binding = 2) uniform sampler2D plane2Texture; + +void main() +{ + float Y = texture(plane1Texture, texCoord).r; + float x = texCoord.x/2.; + float U = texture(plane2Texture, vec2(x, texCoord.y)).r; + float V = texture(plane2Texture, vec2(x + .5, texCoord.y)).r; + vec4 color = vec4(Y, U, V, 1.); + fragColor = ubuf.colorMatrix * color * ubuf.opacity; + +#ifdef QMM_OUTPUTSURFACE_LINEAR + fragColor = convertSRGBToLinear(fragColor); +#endif + + // Clamp output to valid range to account for out-of-range + // input values and numerical inaccuracies in YUV->RGB conversion + fragColor = clamp(fragColor, 0.0, 1.0); +} diff --git a/src/multimedia/shaders/nv12.frag b/src/multimedia/shaders/nv12.frag new file mode 100644 index 000000000..20399d9f0 --- /dev/null +++ b/src/multimedia/shaders/nv12.frag @@ -0,0 +1,27 @@ +#version 440 +#extension GL_GOOGLE_include_directive : enable + +#include "uniformbuffer.glsl" +#include "colortransfer.glsl" + +layout(location = 0) in vec2 texCoord; +layout(location = 0) out vec4 fragColor; + +layout(binding = 1) uniform sampler2D plane1Texture; +layout(binding = 2) uniform sampler2D plane2Texture; + +void main() +{ + float Y = texture(plane1Texture, texCoord).r; + vec2 UV = texture(plane2Texture, texCoord).rg; + vec4 color = vec4(Y, UV.x, UV.y, 1.); + fragColor = ubuf.colorMatrix * color * ubuf.opacity; + +#ifdef QMM_OUTPUTSURFACE_LINEAR + fragColor = convertSRGBToLinear(fragColor); +#endif + + // Clamp output to valid range to account for out-of-range + // input values and numerical inaccuracies in YUV->RGB conversion + fragColor = clamp(fragColor, 0.0, 1.0); +} diff --git a/src/multimedia/shaders/nv12_bt2020_hlg.frag b/src/multimedia/shaders/nv12_bt2020_hlg.frag new file mode 100644 index 000000000..25560c9b7 --- /dev/null +++ b/src/multimedia/shaders/nv12_bt2020_hlg.frag @@ -0,0 +1,42 @@ +#version 440 +#extension GL_GOOGLE_include_directive : enable + +#include "uniformbuffer.glsl" +#include "colortransfer.glsl" +#include "colorconvert.glsl" +#include "hdrtonemapper.glsl" + +layout(location = 0) in vec2 texCoord; +layout(location = 0) out vec4 fragColor; + +layout(binding = 1) uniform sampler2D plane1Texture; +layout(binding = 2) uniform sampler2D plane2Texture; + +// This implements support HDR video using the HLG transfer functions, see also +// https://en.wikipedia.org/wiki/Hybrid_log–gamma +// https://www.itu.int/dms_pub/itu-r/opb/rep/R-REP-BT.2390-6-2019-PDF-E.pdf +// https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.2100-2-201807-I!!PDF-E.pdf +// +// Tonemapping is done using the same algorithm as for the PQ transfer function, but we +// operate in HLG space here. +void main() +{ + float Y = texture(plane1Texture, texCoord).r; + vec2 UV = texture(plane2Texture, texCoord).rg; + // map to Rec.2020 color space + fragColor = vec4(Y, UV.x, UV.y, 1.); + fragColor = ubuf.colorMatrix * fragColor; + + // tonemap + float y = (Y - 16./256.)*256./219.; // Video range (16...235) + float scale = tonemapScaleForLuminosity(y, ubuf.masteringWhite, ubuf.maxLum); + fragColor *= scale; + + fragColor = convertHLGToLinear(fragColor, ubuf.maxLum); + fragColor = convertRec2020ToSRGB(fragColor); + fragColor *= ubuf.opacity; + +#ifndef QMM_OUTPUTSURFACE_LINEAR + fragColor = convertSRGBFromLinear(fragColor); +#endif +} diff --git a/src/multimedia/shaders/nv12_bt2020_pq.frag b/src/multimedia/shaders/nv12_bt2020_pq.frag new file mode 100644 index 000000000..96aef068e --- /dev/null +++ b/src/multimedia/shaders/nv12_bt2020_pq.frag @@ -0,0 +1,48 @@ +#version 440 +#extension GL_GOOGLE_include_directive : enable + +#include "uniformbuffer.glsl" +#include "colortransfer.glsl" +#include "colorconvert.glsl" +#include "hdrtonemapper.glsl" + +layout(location = 0) in vec2 texCoord; +layout(location = 0) out vec4 fragColor; + +layout(binding = 1) uniform sampler2D plane1Texture; +layout(binding = 2) uniform sampler2D plane2Texture; + +// This uses the PQ transfer function, see also https://en.wikipedia.org/wiki/Perceptual_quantizer +// or https://ieeexplore.ieee.org/document/7291452 +// +// Tonemapping into the RGB range supported by the output is done using +// https://www.itu.int/dms_pub/itu-r/opb/rep/R-REP-BT.2390-6-2019-PDF-E.pdf, section 5.4 +// +// masteringWhite in PQ values, not in linear. maxOutLum as defined in the doc above +// we assume that masteringBlack == 0, and minLum == 0 to simplify the calculations +// +// The calculation calculates a new luminosity in non linear space and scales the UV +// components before linearizing. This corresponds to option (2) at the end of section 5.4. +// This option was chosen as it keeps the colors correct while as well as being computationally +// cheapest. +void main() +{ + float Y = texture(plane1Texture, texCoord).r; + vec2 UV = texture(plane2Texture, texCoord).rg; + // map to Rec.2020 color space + fragColor = vec4(Y, UV.x, UV.y, 1.); + fragColor = ubuf.colorMatrix * fragColor; + + // tonemap + float y = (Y - 16./256.)*256./219.; // Video range (16...235) + float scale = tonemapScaleForLuminosity(y, ubuf.masteringWhite, ubuf.maxLum); + fragColor *= scale; + + fragColor = convertPQToLinear(fragColor); + fragColor = convertRec2020ToSRGB(fragColor); + fragColor *= ubuf.opacity; + +#ifndef QMM_OUTPUTSURFACE_LINEAR + fragColor = convertSRGBFromLinear(fragColor); +#endif +} diff --git a/src/multimedia/shaders/nv21.frag b/src/multimedia/shaders/nv21.frag new file mode 100644 index 000000000..c3f641be5 --- /dev/null +++ b/src/multimedia/shaders/nv21.frag @@ -0,0 +1,27 @@ +#version 440 +#extension GL_GOOGLE_include_directive : enable + +#include "uniformbuffer.glsl" +#include "colortransfer.glsl" + +layout(location = 0) in vec2 texCoord; +layout(location = 0) out vec4 fragColor; + +layout(binding = 1) uniform sampler2D plane1Texture; +layout(binding = 2) uniform sampler2D plane2Texture; + +void main() +{ + float Y = texture(plane1Texture, texCoord).r; + vec2 UV = texture(plane2Texture, texCoord).gr; + vec4 color = vec4(Y, UV.x, UV.y, 1.); + fragColor = ubuf.colorMatrix * color * ubuf.opacity; + +#ifdef QMM_OUTPUTSURFACE_LINEAR + fragColor = convertSRGBToLinear(fragColor); +#endif + + // Clamp output to valid range to account for out-of-range + // input values and numerical inaccuracies in YUV->RGB conversion + fragColor = clamp(fragColor, 0.0, 1.0); +} diff --git a/src/multimedia/shaders/rectsampler.vert b/src/multimedia/shaders/rectsampler.vert new file mode 100644 index 000000000..e693370dc --- /dev/null +++ b/src/multimedia/shaders/rectsampler.vert @@ -0,0 +1,16 @@ +#version 440 +#extension GL_GOOGLE_include_directive : enable + +#include "uniformbuffer.glsl" + +layout(location = 0) in vec4 vertexPosition; +layout(location = 1) in vec2 vertexTexCoord; + +layout(location = 0) out vec2 texCoord; + +out gl_PerVertex { vec4 gl_Position; }; + +void main() { + texCoord = (ubuf.colorMatrix * vec4(vertexTexCoord, 0.0, 1.0)).xy; + gl_Position = ubuf.matrix * vertexPosition; +} diff --git a/src/multimedia/shaders/rectsampler_bgra.frag b/src/multimedia/shaders/rectsampler_bgra.frag new file mode 100644 index 000000000..8b1b9a4ad --- /dev/null +++ b/src/multimedia/shaders/rectsampler_bgra.frag @@ -0,0 +1,19 @@ +#version 440 +#extension GL_GOOGLE_include_directive : enable + +#include "uniformbuffer.glsl" +#include "colortransfer.glsl" + +layout(location = 0) in vec2 texCoord; +layout(location = 0) out vec4 fragColor; + +layout(binding = 1) uniform sampler2DRect rgbTexture; + +void main() +{ + fragColor = texture(rgbTexture, texCoord).rgba * ubuf.opacity; + +#ifdef QMM_OUTPUTSURFACE_LINEAR + fragColor = convertSRGBToLinear(fragColor); +#endif +} diff --git a/src/multimedia/shaders/rgba.frag b/src/multimedia/shaders/rgba.frag new file mode 100644 index 000000000..b53e0dc71 --- /dev/null +++ b/src/multimedia/shaders/rgba.frag @@ -0,0 +1,19 @@ +#version 440 +#extension GL_GOOGLE_include_directive : enable + +#include "uniformbuffer.glsl" +#include "colortransfer.glsl" + +layout(location = 0) in vec2 texCoord; +layout(location = 0) out vec4 fragColor; + +layout(binding = 1) uniform sampler2D rgbTexture; + +void main() +{ + fragColor = ubuf.colorMatrix * texture(rgbTexture, texCoord).rgba * ubuf.opacity; + +#ifdef QMM_OUTPUTSURFACE_LINEAR + fragColor = convertSRGBToLinear(fragColor); +#endif +} diff --git a/src/multimedia/shaders/uniformbuffer.glsl b/src/multimedia/shaders/uniformbuffer.glsl new file mode 100644 index 000000000..c74859c5d --- /dev/null +++ b/src/multimedia/shaders/uniformbuffer.glsl @@ -0,0 +1,11 @@ +// Make sure to also modify externalsampler_gles.frag when modifying this + +layout(std140, binding = 0) uniform buf { + mat4 matrix; + mat4 colorMatrix; + float opacity; + float width; + // HDR metadata required for tonemapping + float masteringWhite; // in PQ or HLG values + float maxLum; // in PQ or HLG values +} ubuf; diff --git a/src/multimedia/shaders/uyvy.frag b/src/multimedia/shaders/uyvy.frag new file mode 100644 index 000000000..26a83da3f --- /dev/null +++ b/src/multimedia/shaders/uyvy.frag @@ -0,0 +1,27 @@ +#version 440 +#extension GL_GOOGLE_include_directive : enable + +#include "uniformbuffer.glsl" +#include "colortransfer.glsl" + +layout(location = 0) in vec2 texCoord; +layout(location = 0) out vec4 fragColor; + +layout(binding = 1) uniform sampler2D plane1Texture; + +void main() +{ + int x = int(floor(texCoord.x * ubuf.width)); + bool rightSubPixel = (x/2*2 != x); + float Y = rightSubPixel ? texture(plane1Texture, texCoord).a : texture(plane1Texture, texCoord).g; + vec2 UV = texture(plane1Texture, texCoord).rb; + fragColor = ubuf.colorMatrix * vec4(Y, UV, 1.0) * ubuf.opacity; + +#ifdef QMM_OUTPUTSURFACE_LINEAR + fragColor = convertSRGBToLinear(fragColor); +#endif + + // Clamp output to valid range to account for out-of-range + // input values and numerical inaccuracies in YUV->RGB conversion + fragColor = clamp(fragColor, 0.0, 1.0); +} diff --git a/src/multimedia/shaders/vertex.vert b/src/multimedia/shaders/vertex.vert new file mode 100644 index 000000000..ce170824e --- /dev/null +++ b/src/multimedia/shaders/vertex.vert @@ -0,0 +1,16 @@ +#version 440 +#extension GL_GOOGLE_include_directive : enable + +#include "uniformbuffer.glsl" + +layout(location = 0) in vec4 vertexPosition; +layout(location = 1) in vec2 vertexTexCoord; + +layout(location = 0) out vec2 texCoord; + +out gl_PerVertex { vec4 gl_Position; }; + +void main() { + texCoord = vertexTexCoord; + gl_Position = ubuf.matrix * vertexPosition; +} diff --git a/src/multimedia/shaders/y.frag b/src/multimedia/shaders/y.frag new file mode 100644 index 000000000..8c25fc762 --- /dev/null +++ b/src/multimedia/shaders/y.frag @@ -0,0 +1,25 @@ +#version 440 +#extension GL_GOOGLE_include_directive : enable + +#include "uniformbuffer.glsl" +#include "colortransfer.glsl" + +layout(location = 0) in vec2 texCoord; +layout(location = 0) out vec4 fragColor; + +layout(binding = 1) uniform sampler2D plane1Texture; + +void main() +{ + float Y = texture(plane1Texture, texCoord).r; + vec4 color = vec4(Y, Y, Y, 1.); + fragColor = ubuf.colorMatrix * color * ubuf.opacity; + +#ifdef QMM_OUTPUTSURFACE_LINEAR + fragColor = convertSRGBToLinear(fragColor); +#endif + + // Clamp output to valid range to account for out-of-range + // input values and numerical inaccuracies in YUV->RGB conversion + fragColor = clamp(fragColor, 0.0, 1.0); +} diff --git a/src/multimedia/shaders/yuv_triplanar.frag b/src/multimedia/shaders/yuv_triplanar.frag new file mode 100644 index 000000000..228147943 --- /dev/null +++ b/src/multimedia/shaders/yuv_triplanar.frag @@ -0,0 +1,29 @@ +#version 440 +#extension GL_GOOGLE_include_directive : enable + +#include "uniformbuffer.glsl" +#include "colortransfer.glsl" + +layout(location = 0) in vec2 texCoord; +layout(location = 0) out vec4 fragColor; + +layout(binding = 1) uniform sampler2D plane1Texture; +layout(binding = 2) uniform sampler2D plane2Texture; +layout(binding = 3) uniform sampler2D plane3Texture; + +void main() +{ + float Y = texture(plane1Texture, texCoord).r; + float U = texture(plane2Texture, texCoord).r; + float V = texture(plane3Texture, texCoord).r; + vec4 color = vec4(Y, U, V, 1.); + fragColor = ubuf.colorMatrix * color * ubuf.opacity; + +#ifdef QMM_OUTPUTSURFACE_LINEAR + fragColor = convertSRGBToLinear(fragColor); +#endif + + // Clamp output to valid range to account for out-of-range + // input values and numerical inaccuracies in YUV->RGB conversion + fragColor = clamp(fragColor, 0.0, 1.0); +} diff --git a/src/multimedia/shaders/yuv_triplanar_p10.frag b/src/multimedia/shaders/yuv_triplanar_p10.frag new file mode 100644 index 000000000..5da0ed339 --- /dev/null +++ b/src/multimedia/shaders/yuv_triplanar_p10.frag @@ -0,0 +1,29 @@ +#version 440 +#extension GL_GOOGLE_include_directive : enable + +#include "uniformbuffer.glsl" +#include "colortransfer.glsl" + +layout(location = 0) in vec2 texCoord; +layout(location = 0) out vec4 fragColor; + +layout(binding = 1) uniform sampler2D plane1Texture; +layout(binding = 2) uniform sampler2D plane2Texture; +layout(binding = 3) uniform sampler2D plane3Texture; + +void main() +{ + float Y = texture(plane1Texture, texCoord).r * 64; + float U = texture(plane2Texture, texCoord).r * 64; + float V = texture(plane3Texture, texCoord).r * 64; + vec4 color = vec4(Y, U, V, 1.); + fragColor = ubuf.colorMatrix * color * ubuf.opacity; + +#ifdef QMM_OUTPUTSURFACE_LINEAR + fragColor = convertSRGBToLinear(fragColor); +#endif + + // Clamp output to valid range to account for out-of-range + // input values and numerical inaccuracies in YUV->RGB conversion + fragColor = clamp(fragColor, 0.0, 1.0); +} diff --git a/src/multimedia/shaders/yuyv.frag b/src/multimedia/shaders/yuyv.frag new file mode 100644 index 000000000..0f6e65b6d --- /dev/null +++ b/src/multimedia/shaders/yuyv.frag @@ -0,0 +1,27 @@ +#version 440 +#extension GL_GOOGLE_include_directive : enable + +#include "uniformbuffer.glsl" +#include "colortransfer.glsl" + +layout(location = 0) in vec2 texCoord; +layout(location = 0) out vec4 fragColor; + +layout(binding = 1) uniform sampler2D plane1Texture; + +void main() +{ + int x = int(floor(texCoord.x * ubuf.width)); + bool rightSubPixel = (x/2*2 != x); + float Y = rightSubPixel ? texture(plane1Texture, texCoord).b : texture(plane1Texture, texCoord).r; + vec2 UV = texture(plane1Texture, texCoord).ga; + fragColor = ubuf.colorMatrix * vec4(Y, UV, 1.0) * ubuf.opacity; + +#ifdef QMM_OUTPUTSURFACE_LINEAR + fragColor = convertSRGBToLinear(fragColor); +#endif + + // Clamp output to valid range to account for out-of-range + // input values and numerical inaccuracies in YUV->RGB conversion + fragColor = clamp(fragColor, 0.0, 1.0); +} diff --git a/src/multimedia/shaders/yvu_triplanar.frag b/src/multimedia/shaders/yvu_triplanar.frag new file mode 100644 index 000000000..ac2cbdf63 --- /dev/null +++ b/src/multimedia/shaders/yvu_triplanar.frag @@ -0,0 +1,29 @@ +#version 440 +#extension GL_GOOGLE_include_directive : enable + +#include "uniformbuffer.glsl" +#include "colortransfer.glsl" + +layout(location = 0) in vec2 texCoord; +layout(location = 0) out vec4 fragColor; + +layout(binding = 1) uniform sampler2D plane1Texture; +layout(binding = 2) uniform sampler2D plane2Texture; +layout(binding = 3) uniform sampler2D plane3Texture; + +void main() +{ + float Y = texture(plane1Texture, texCoord).r; + float V = texture(plane2Texture, texCoord).r; + float U = texture(plane3Texture, texCoord).r; + vec4 color = vec4(Y, U, V, 1.); + fragColor = ubuf.colorMatrix * color * ubuf.opacity; + +#ifdef QMM_OUTPUTSURFACE_LINEAR + fragColor = convertSRGBToLinear(fragColor); +#endif + + // Clamp output to valid range to account for out-of-range + // input values and numerical inaccuracies in YUV->RGB conversion + fragColor = clamp(fragColor, 0.0, 1.0); +} |