/*
Phaneron media compositing software.
Original work Copyright (C) 2020 Streampunk Media Ltd.
Based on work from [Streampunk Media Ltd.](https://github.com/Streampunk/phaneron)
Further work Copyright (C) 2023 SuperFlyTV AB.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
__constant sampler_t sampler1 =
CLK_NORMALIZED_COORDS_FALSE
| CLK_ADDRESS_CLAMP_TO_EDGE
| CLK_FILTER_NEAREST
float4 spatial_predictor(
float4 a, float4 b, float4 c, float4 d,
float4 e, float4 f, float4 g, float4 h,
float4 i, float4 j, float4 k, float4 l,
float4 m, float4 n
) {
float4 spatialPred = (d + k) / 2.0f float4 spatialScore = fabs(c - j) + fabs(d - k) + fabs(e - l)
float4 score = fabs(b - k) + fabs(c - l) + fabs(d - m) int4 compareScore = score < spatialScore spatialPred = compareScore ? (c + l) / 2.0f : spatialPred spatialScore = compareScore ? score : spatialScore score = compareScore ? fabs(a - l) + fabs(b - m) + fabs(c - n) : score compareScore = compareScore && (score < spatialScore) spatialPred = compareScore ? (b + m) / 2.0f : spatialPred spatialScore = compareScore ? score : spatialScore
score = fabs(d - i) + fabs(e - j) + fabs(f - k) compareScore = score < spatialScore spatialPred = compareScore ? (e + j) / 2.0f : spatialPred spatialScore = compareScore ? score : spatialScore score = compareScore ? fabs(e - h) + fabs(f - i) + fabs(g - j) : score compareScore = compareScore && (score < spatialScore) spatialPred = compareScore ? (f + i) / 2.0f : spatialPred spatialScore = compareScore ? score : spatialScore
return spatialPred}
float4 fmax3(float4 a, float4 b, float4 c) {
return fmax(fmax(a, b), c)}
float4 fmin3(float4 a, float4 b, float4 c) {
return fmin(fmin(a, b), c)}
float4 temporal_predictor(
float4 A, float4 B, float4 C, float4 D,
float4 E, float4 F, float4 G, float4 H,
float4 I, float4 J, float4 K, float4 L,
float4 spatialPred, int skipCheck
) {
float4 p0 = (C + H) / 2.0f float4 p1 = F float4 p2 = (D + I) / 2.0f float4 p3 = G float4 p4 = (E + J) / 2.0f
float4 tdiff0 = fabs(D - I) float4 tdiff1 = (fabs(A - F) + fabs(B - G)) / 2.0f float4 tdiff2 = (fabs(K - F) + fabs(G - L)) / 2.0f
float4 diff = fmax3(tdiff0, tdiff1, tdiff2)
if (!skipCheck) {
float4 p2mp3 = p2 - p3 float4 p2mp1 = p2 - p1 float4 p0mp1 = p0 - p1 float4 p4mp3 = p4 - p3 float4 maxi = fmax3(p2mp3, p2mp1, fmin(p0mp1, p4mp3)) float4 mini = fmin3(p2mp3, p2mp1, fmax(p0mp1, p4mp3)) diff = fmax3(diff, mini, -maxi) }
spatialPred = (spatialPred > (p2 + diff)) ? p2 + diff : spatialPred spatialPred = (spatialPred < (p2 - diff)) ? p2 - diff : spatialPred return spatialPred}
__kernel void yadif(
__read_only image2d_t prev,
__read_only image2d_t cur,
__read_only image2d_t next,
__private int parity,
__private int tff,
__private int skipSpatial,
__write_only image2d_t output
) {
int xo = get_global_id(0) int yo = get_global_id(1)
// Don't modify the primary field
if (yo % 2 == parity) {
write_imagef(output, (int2)(xo, yo), read_imagef(cur, sampler1, (int2) (xo, yo))) return }
// Calculate spatial prediction
float4 a = read_imagef(cur, sampler1, (int2) (xo - 3, yo - 1)) float4 b = read_imagef(cur, sampler1, (int2) (xo - 2, yo - 1)) float4 c = read_imagef(cur, sampler1, (int2) (xo - 1, yo - 1)) float4 d = read_imagef(cur, sampler1, (int2) (xo - 0, yo - 1)) float4 e = read_imagef(cur, sampler1, (int2) (xo + 1, yo - 1)) float4 f = read_imagef(cur, sampler1, (int2) (xo + 2, yo - 1)) float4 g = read_imagef(cur, sampler1, (int2) (xo + 3, yo - 1))
float4 h = read_imagef(cur, sampler1, (int2) (xo - 3, yo + 1)) float4 i = read_imagef(cur, sampler1, (int2) (xo - 2, yo + 1)) float4 j = read_imagef(cur, sampler1, (int2) (xo - 1, yo + 1)) float4 k = read_imagef(cur, sampler1, (int2) (xo - 0, yo + 1)) float4 l = read_imagef(cur, sampler1, (int2) (xo + 1, yo + 1)) float4 m = read_imagef(cur, sampler1, (int2) (xo + 2, yo + 1)) float4 n = read_imagef(cur, sampler1, (int2) (xo + 3, yo + 1))
float4 spatialPred = spatial_predictor(a, b, c, d, e, f, g, h, i, j, k, l, m, n)
// Calculate temporal prediction
int isSecondField = !(parity ^ tff)
float4 A = read_imagef(prev, sampler1, (int2) (xo, yo - 1)) float4 B = read_imagef(prev, sampler1, (int2) (xo, yo + 1)) float4 C = isSecondField ? read_imagef(cur, sampler1, (int2) (xo, yo - 2)) : read_imagef(prev, sampler1, (int2) (xo, yo - 2)) float4 D = isSecondField ? read_imagef(cur, sampler1, (int2) (xo, yo + 0)) : read_imagef(prev, sampler1, (int2) (xo, yo + 0)) float4 E = isSecondField ? read_imagef(cur, sampler1, (int2) (xo, yo + 2)) : read_imagef(prev, sampler1, (int2) (xo, yo + 2)) float4 F = read_imagef(cur, sampler1, (int2) (xo, yo - 1)) float4 G = read_imagef(cur, sampler1, (int2) (xo, yo + 1)) float4 H = isSecondField ? read_imagef(next, sampler1, (int2) (xo, yo - 2)) : read_imagef(cur, sampler1, (int2) (xo, yo - 2)) float4 I = isSecondField ? read_imagef(next, sampler1, (int2) (xo, yo + 0)) : read_imagef(cur, sampler1, (int2) (xo, yo + 0)) float4 J = isSecondField ? read_imagef(next, sampler1, (int2) (xo, yo + 2)) : read_imagef(cur, sampler1, (int2) (xo, yo + 2)) float4 K = read_imagef(next, sampler1, (int2) (xo, yo - 1)) float4 L = read_imagef(next, sampler1, (int2) (xo, yo + 1))
spatialPred = temporal_predictor(
A, B, C, D, E, F, G, H, I, J, K, L,
spatialPred, skipSpatial
) // Reset Alpha
spatialPred.s3 = read_imagef(cur, sampler1, (int2) (xo, yo)).s3
write_imagef(output, (int2)(xo, yo), spatialPred)}