1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
media / gpu / chromeos / shaders / MT2TShader.frag [blame]
// Frag shader for MT2T->AR30 conversion.
#version 450
#extension GL_EXT_samplerless_texture_functions : require
precision mediump float;
precision mediump int;
layout(location = 0) in vec2 intraTileX;
layout(location = 1) in vec2 intraTileY;
layout(location = 2) in flat highp vec2 yOffset;
layout(location = 3) in flat highp vec2 xOffset;
layout(location = 0) out vec4 outColor;
layout( push_constant ) uniform constants {
layout(offset = 24) highp vec2 planeStrides;
} pushConstants;
layout(binding = 0) uniform texture2D lumaTexture;
layout(binding = 1) uniform texture2D chromaTexture;
const mat3 colorConversion = mat3(1.164, 1.164, 1.164,
0.0, -0.391, 2.018,
1.596, -0.813, 0.0);
void main() {
vec2 blockIdx = floor(intraTileY / 4.0);
vec2 blockRowIdx = intraTileY - (blockIdx * 4.0);
// MSB indices need to be adjusted by how many LSB bytes are serialized
// before the current MSB. Every 64 pixel block starts with 16 bytes of LSB
// data.
highp vec2 msbLinearIdx = (floor(intraTileY) * vec2(16, 8)) +
floor(intraTileX) + xOffset;
msbLinearIdx += (blockIdx + 1.0) * vec2(16, 8);
// Likewise, we need to find the address of our LSB byte. Since each LSB byte
// encodes the LSBs for a 1x4 mini-tile, we can compute a base address using
// blockIdx * 16 bytes, and then offset it by the intra tile X coordinate.
highp vec2 lsbLinearIdx = blockIdx * vec2(80, 40) + xOffset;
lsbLinearIdx += floor(intraTileX);
// 0.5 is a floating point issue fudge factor.
highp vec4 linearIdx = vec4(msbLinearIdx, lsbLinearIdx);
highp vec4 strides = vec4(pushConstants.planeStrides,
pushConstants.planeStrides);
highp vec4 detiledY = floor(linearIdx / strides);
highp vec4 detiledX = linearIdx - (detiledY * strides);
detiledY += vec4(yOffset, yOffset);
vec3 yuv;
yuv.r = texelFetch(lumaTexture, ivec2(detiledX.r, detiledY.r), 0).r;
yuv.gb = texelFetch(chromaTexture, ivec2(detiledX.g, detiledY.g), 0).rg;
vec3 yuvLsb;
yuvLsb.r = texelFetch(lumaTexture, ivec2(detiledX.b, detiledY.b), 0).r;
yuvLsb.gb = texelFetch(chromaTexture, ivec2(detiledX.a, detiledY.a), 0).rg;
// LSBs are packed into their corresponding byte with the top of the tile
// packed into the least significant 2 bits of the byte first. So ideally,
// we would bit shift the LSB byte based on what row within the block the
// current pixel is in, mask all but the lower two bits, and then shift those
// bits into where they need to go. But, because both texelFetch and outColor
// are floating points, this requires integer conversions, which can be quite
// slow. So instead, we use a multiplication to emulate a left shift, then
// fract() to emulate discarding the bits that were shifted too high for
// the register, and then division (multiplication by the reciprocal) to
// emulate a right shift. The left shift constant should be
// 2^(2*(3-blockRowIdx)), and the right shift constant should be 2^-8 in
// order for this to work. The one hitch is that the floating point color
// values range from 0.0 to 1.0, but baked into our bit shifting trick is
// the assumption that the colors range from 0.0 to 255.0/256.0 and 0.0 to
// 1023.0/1024.0 respectively. We can fix this by factoring into our shift
// multiplication constants the conversion terms 255.0/256.0 and
// 1024.0/1023.0.
//
// Note that the nature of floating point division means we don't emulate
// discarding bits that are shifted too low, we just keep them as a tiny
// fractional component. This means this approach is only approximately
// correct. But, it is guaranteed to be correct within 1/1024, which is
// all we need for 10-bit color accuracy.
vec3 shift = ldexp(vec2((255.0/256.0)), ivec2(2.0 * (3.0 - blockRowIdx))).rgg;
yuvLsb *= shift;
yuvLsb = fract(yuvLsb);
yuvLsb *= (1.0 / 256.0 * 1024.0 / 1023.0);
yuv += yuvLsb;
yuv.r -= 16.0/255.0;
yuv.gb -= vec2(0.5, 0.5);
outColor = vec4(colorConversion * yuv, 1.0);
}