xref: /aosp_15_r20/external/mesa3d/src/compiler/glsl/astc_decoder.glsl (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1*61046927SAndroid Build Coastguard Worker#version 320 es
2*61046927SAndroid Build Coastguard Workerprecision highp float;
3*61046927SAndroid Build Coastguard Workerprecision highp int;
4*61046927SAndroid Build Coastguard Workerprecision highp usamplerBuffer;
5*61046927SAndroid Build Coastguard Workerprecision highp usampler2D;
6*61046927SAndroid Build Coastguard Workerprecision highp image2D;
7*61046927SAndroid Build Coastguard Workerprecision highp uimage2D;
8*61046927SAndroid Build Coastguard Worker
9*61046927SAndroid Build Coastguard Worker/* Copyright (c) 2020-2022 Hans-Kristian Arntzen
10*61046927SAndroid Build Coastguard Worker * Copyright (c) 2022 Intel Corporation
11*61046927SAndroid Build Coastguard Worker *
12*61046927SAndroid Build Coastguard Worker * Permission is hereby granted, free of charge, to any person obtaining
13*61046927SAndroid Build Coastguard Worker * a copy of this software and associated documentation files (the
14*61046927SAndroid Build Coastguard Worker * "Software"), to deal in the Software without restriction, including
15*61046927SAndroid Build Coastguard Worker * without limitation the rights to use, copy, modify, merge, publish,
16*61046927SAndroid Build Coastguard Worker * distribute, sublicense, and/or sell copies of the Software, and to
17*61046927SAndroid Build Coastguard Worker * permit persons to whom the Software is furnished to do so, subject to
18*61046927SAndroid Build Coastguard Worker * the following conditions:
19*61046927SAndroid Build Coastguard Worker *
20*61046927SAndroid Build Coastguard Worker * The above copyright notice and this permission notice shall be
21*61046927SAndroid Build Coastguard Worker * included in all copies or substantial portions of the Software.
22*61046927SAndroid Build Coastguard Worker *
23*61046927SAndroid Build Coastguard Worker * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24*61046927SAndroid Build Coastguard Worker * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25*61046927SAndroid Build Coastguard Worker * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
26*61046927SAndroid Build Coastguard Worker * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
27*61046927SAndroid Build Coastguard Worker * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
28*61046927SAndroid Build Coastguard Worker * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
29*61046927SAndroid Build Coastguard Worker * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30*61046927SAndroid Build Coastguard Worker */
31*61046927SAndroid Build Coastguard Worker
32*61046927SAndroid Build Coastguard Worker#ifdef VULKAN
33*61046927SAndroid Build Coastguard Worker
34*61046927SAndroid Build Coastguard Workerprecision highp utextureBuffer;
35*61046927SAndroid Build Coastguard Workerprecision highp utexture2DArray;
36*61046927SAndroid Build Coastguard Workerprecision highp uimage2DArray;
37*61046927SAndroid Build Coastguard Workerprecision highp uimage3D;
38*61046927SAndroid Build Coastguard Workerprecision highp utexture3D;
39*61046927SAndroid Build Coastguard Worker
40*61046927SAndroid Build Coastguard Worker#extension GL_EXT_samplerless_texture_functions : require
41*61046927SAndroid Build Coastguard Workerlayout(local_size_x_id = 0, local_size_y_id = 1, local_size_z = 4) in;
42*61046927SAndroid Build Coastguard Worker
43*61046927SAndroid Build Coastguard Workerlayout(set = 0, binding = 0) writeonly uniform uimage2DArray OutputImage2Darray;
44*61046927SAndroid Build Coastguard Workerlayout(set = 0, binding = 0) writeonly uniform uimage3D OutputImage3D;
45*61046927SAndroid Build Coastguard Workerlayout(set = 0, binding = 1) uniform utexture2DArray PayloadInput2Darray;
46*61046927SAndroid Build Coastguard Workerlayout(set = 0, binding = 1) uniform utexture3D PayloadInput3D;
47*61046927SAndroid Build Coastguard Workerlayout(set = 0, binding = 2) uniform utextureBuffer LUTRemainingBitsToEndpointQuantizer;
48*61046927SAndroid Build Coastguard Workerlayout(set = 0, binding = 3) uniform utextureBuffer LUTEndpointUnquantize;
49*61046927SAndroid Build Coastguard Workerlayout(set = 0, binding = 4) uniform utextureBuffer LUTWeightQuantizer;
50*61046927SAndroid Build Coastguard Workerlayout(set = 0, binding = 5) uniform utextureBuffer LUTWeightUnquantize;
51*61046927SAndroid Build Coastguard Workerlayout(set = 0, binding = 6) uniform utextureBuffer LUTTritQuintDecode;
52*61046927SAndroid Build Coastguard Workerlayout(set = 0, binding = 7) uniform utextureBuffer LUTPartitionTable;
53*61046927SAndroid Build Coastguard Worker
54*61046927SAndroid Build Coastguard Workerlayout(constant_id = 2) const bool DECODE_8BIT = false;
55*61046927SAndroid Build Coastguard Worker
56*61046927SAndroid Build Coastguard Workerlayout(push_constant, std430) uniform pc {
57*61046927SAndroid Build Coastguard Worker   ivec2 texel_blk_start;
58*61046927SAndroid Build Coastguard Worker   ivec2 texel_end;
59*61046927SAndroid Build Coastguard Worker   bool is_3Dimage;
60*61046927SAndroid Build Coastguard Worker};
61*61046927SAndroid Build Coastguard Worker
62*61046927SAndroid Build Coastguard Worker#else /* VULKAN */
63*61046927SAndroid Build Coastguard Worker
64*61046927SAndroid Build Coastguard Workerlayout(local_size_x = %u, local_size_y = %u, local_size_z = 4) in;
65*61046927SAndroid Build Coastguard Worker
66*61046927SAndroid Build Coastguard Worker#define utextureBuffer usamplerBuffer
67*61046927SAndroid Build Coastguard Worker#define utexture2D usampler2D
68*61046927SAndroid Build Coastguard Worker
69*61046927SAndroid Build Coastguard Workerlayout(binding = 0) uniform utextureBuffer LUTRemainingBitsToEndpointQuantizer;
70*61046927SAndroid Build Coastguard Workerlayout(binding = 1) uniform utextureBuffer LUTEndpointUnquantize;
71*61046927SAndroid Build Coastguard Workerlayout(binding = 2) uniform utextureBuffer LUTWeightQuantizer;
72*61046927SAndroid Build Coastguard Workerlayout(binding = 3) uniform utextureBuffer LUTWeightUnquantize;
73*61046927SAndroid Build Coastguard Workerlayout(binding = 4) uniform utextureBuffer LUTTritQuintDecode;
74*61046927SAndroid Build Coastguard Workerlayout(binding = 5) uniform utexture2D LUTPartitionTable;
75*61046927SAndroid Build Coastguard Workerlayout(binding = 6) uniform utexture2D PayloadInput;
76*61046927SAndroid Build Coastguard Worker
77*61046927SAndroid Build Coastguard Workerlayout(rgba8ui, binding = 7) writeonly uniform uimage2D OutputImage;
78*61046927SAndroid Build Coastguard Workerconst bool DECODE_8BIT = true;
79*61046927SAndroid Build Coastguard Worker
80*61046927SAndroid Build Coastguard Worker#endif /* VULKAN */
81*61046927SAndroid Build Coastguard Worker
82*61046927SAndroid Build Coastguard Workerconst int MODE_LDR = 0;
83*61046927SAndroid Build Coastguard Workerconst int MODE_HDR = 1;
84*61046927SAndroid Build Coastguard Workerconst int MODE_HDR_LDR_ALPHA = 2;
85*61046927SAndroid Build Coastguard Worker
86*61046927SAndroid Build Coastguard Workerconst uvec4 error_color = uvec4(255, 0, 255, 255);
87*61046927SAndroid Build Coastguard Worker
88*61046927SAndroid Build Coastguard Worker/* bitextract.h */
89*61046927SAndroid Build Coastguard Workerint extract_bits(uvec4 payload, int offset, int bits)
90*61046927SAndroid Build Coastguard Worker{
91*61046927SAndroid Build Coastguard Worker        int last_offset = offset + bits - 1;
92*61046927SAndroid Build Coastguard Worker        int result;
93*61046927SAndroid Build Coastguard Worker
94*61046927SAndroid Build Coastguard Worker        if (bits <= 0)
95*61046927SAndroid Build Coastguard Worker                result = 0;
96*61046927SAndroid Build Coastguard Worker        else if ((last_offset >> 5) == (offset >> 5))
97*61046927SAndroid Build Coastguard Worker                result = int(bitfieldExtract(payload[offset >> 5], offset & 31, bits));
98*61046927SAndroid Build Coastguard Worker        else
99*61046927SAndroid Build Coastguard Worker        {
100*61046927SAndroid Build Coastguard Worker                int first_bits = 32 - (offset & 31);
101*61046927SAndroid Build Coastguard Worker                int result_first = int(bitfieldExtract(payload[offset >> 5], offset & 31, first_bits));
102*61046927SAndroid Build Coastguard Worker                int result_second = int(bitfieldExtract(payload[(offset >> 5) + 1], 0, bits - first_bits));
103*61046927SAndroid Build Coastguard Worker                result = result_first | (result_second << first_bits);
104*61046927SAndroid Build Coastguard Worker        }
105*61046927SAndroid Build Coastguard Worker        return result;
106*61046927SAndroid Build Coastguard Worker}
107*61046927SAndroid Build Coastguard Worker
108*61046927SAndroid Build Coastguard Worker/* bitextract.h */
109*61046927SAndroid Build Coastguard Workerint extract_bits_sign(uvec4 payload, int offset, int bits)
110*61046927SAndroid Build Coastguard Worker{
111*61046927SAndroid Build Coastguard Worker        int last_offset = offset + bits - 1;
112*61046927SAndroid Build Coastguard Worker        int result;
113*61046927SAndroid Build Coastguard Worker
114*61046927SAndroid Build Coastguard Worker        if (bits <= 0)
115*61046927SAndroid Build Coastguard Worker                result = 0;
116*61046927SAndroid Build Coastguard Worker        else if ((last_offset >> 5) == (offset >> 5))
117*61046927SAndroid Build Coastguard Worker                result = bitfieldExtract(int(payload[offset >> 5]), offset & 31, bits);
118*61046927SAndroid Build Coastguard Worker        else
119*61046927SAndroid Build Coastguard Worker        {
120*61046927SAndroid Build Coastguard Worker                int first_bits = 32 - (offset & 31);
121*61046927SAndroid Build Coastguard Worker                int result_first = int(bitfieldExtract(payload[offset >> 5], offset & 31, first_bits));
122*61046927SAndroid Build Coastguard Worker                int result_second = bitfieldExtract(int(payload[(offset >> 5) + 1]), 0, bits - first_bits);
123*61046927SAndroid Build Coastguard Worker                result = result_first | (result_second << first_bits);
124*61046927SAndroid Build Coastguard Worker        }
125*61046927SAndroid Build Coastguard Worker        return result;
126*61046927SAndroid Build Coastguard Worker}
127*61046927SAndroid Build Coastguard Worker
128*61046927SAndroid Build Coastguard Worker/* bitextract.h */
129*61046927SAndroid Build Coastguard Workerint extract_bits_reverse(uvec4 payload, int offset, int bits)
130*61046927SAndroid Build Coastguard Worker{
131*61046927SAndroid Build Coastguard Worker        int last_offset = offset + bits - 1;
132*61046927SAndroid Build Coastguard Worker        int result;
133*61046927SAndroid Build Coastguard Worker
134*61046927SAndroid Build Coastguard Worker        if (bits <= 0)
135*61046927SAndroid Build Coastguard Worker                result = 0;
136*61046927SAndroid Build Coastguard Worker        else if ((last_offset >> 5) == (offset >> 5))
137*61046927SAndroid Build Coastguard Worker                result = int(bitfieldReverse(bitfieldExtract(payload[offset >> 5], offset & 31, bits)) >> (32 - bits));
138*61046927SAndroid Build Coastguard Worker        else
139*61046927SAndroid Build Coastguard Worker        {
140*61046927SAndroid Build Coastguard Worker                int first_bits = 32 - (offset & 31);
141*61046927SAndroid Build Coastguard Worker                uint result_first = bitfieldExtract(payload[offset >> 5], offset & 31, first_bits);
142*61046927SAndroid Build Coastguard Worker                uint result_second = bitfieldExtract(payload[(offset >> 5) + 1], 0, bits - first_bits);
143*61046927SAndroid Build Coastguard Worker                result = int(bitfieldReverse(result_first | (result_second << first_bits)) >> (32 - bits));
144*61046927SAndroid Build Coastguard Worker        }
145*61046927SAndroid Build Coastguard Worker        return result;
146*61046927SAndroid Build Coastguard Worker}
147*61046927SAndroid Build Coastguard Worker
148*61046927SAndroid Build Coastguard Workervoid swap(inout int a, inout int b)
149*61046927SAndroid Build Coastguard Worker{
150*61046927SAndroid Build Coastguard Worker    int tmp = a;
151*61046927SAndroid Build Coastguard Worker    a = b;
152*61046927SAndroid Build Coastguard Worker    b = tmp;
153*61046927SAndroid Build Coastguard Worker}
154*61046927SAndroid Build Coastguard Worker
155*61046927SAndroid Build Coastguard Workerivec4 build_coord()
156*61046927SAndroid Build Coastguard Worker{
157*61046927SAndroid Build Coastguard Worker    ivec2 payload_coord = ivec2(gl_WorkGroupID.xy) * 2;
158*61046927SAndroid Build Coastguard Worker    payload_coord.x += int(gl_LocalInvocationID.z) & 1;
159*61046927SAndroid Build Coastguard Worker    payload_coord.y += (int(gl_LocalInvocationID.z) >> 1) & 1;
160*61046927SAndroid Build Coastguard Worker#ifdef VULKAN
161*61046927SAndroid Build Coastguard Worker    payload_coord += texel_blk_start;
162*61046927SAndroid Build Coastguard Worker#endif /* VULKAN */
163*61046927SAndroid Build Coastguard Worker    ivec2 coord = payload_coord * ivec2(gl_WorkGroupSize.xy);
164*61046927SAndroid Build Coastguard Worker    coord += ivec2(gl_LocalInvocationID.xy);
165*61046927SAndroid Build Coastguard Worker    return ivec4(coord, payload_coord);
166*61046927SAndroid Build Coastguard Worker}
167*61046927SAndroid Build Coastguard Worker
168*61046927SAndroid Build Coastguard Workerivec4 interpolate_endpoint(ivec4 ep0, ivec4 ep1, ivec4 weight, int decode_mode)
169*61046927SAndroid Build Coastguard Worker{
170*61046927SAndroid Build Coastguard Worker    if (decode_mode == MODE_HDR)
171*61046927SAndroid Build Coastguard Worker    {
172*61046927SAndroid Build Coastguard Worker        ep0 <<= 4;
173*61046927SAndroid Build Coastguard Worker        ep1 <<= 4;
174*61046927SAndroid Build Coastguard Worker    }
175*61046927SAndroid Build Coastguard Worker    else if (decode_mode == MODE_HDR_LDR_ALPHA)
176*61046927SAndroid Build Coastguard Worker    {
177*61046927SAndroid Build Coastguard Worker        ep0.rgb <<= 4;
178*61046927SAndroid Build Coastguard Worker        ep1.rgb <<= 4;
179*61046927SAndroid Build Coastguard Worker        ep0.a *= 0x101;
180*61046927SAndroid Build Coastguard Worker        ep1.a *= 0x101;
181*61046927SAndroid Build Coastguard Worker    }
182*61046927SAndroid Build Coastguard Worker    else if (DECODE_8BIT)
183*61046927SAndroid Build Coastguard Worker    {
184*61046927SAndroid Build Coastguard Worker        // This isn't quite right in all cases.
185*61046927SAndroid Build Coastguard Worker        // In normal ASTC with sRGB, the alpha channel is supposed to
186*61046927SAndroid Build Coastguard Worker        // be decoded as FP16,
187*61046927SAndroid Build Coastguard Worker        // even when color components are SRGB 8-bit (?!?!?!?!).
188*61046927SAndroid Build Coastguard Worker        // This is correct if decode_unorm8 mode is used though,
189*61046927SAndroid Build Coastguard Worker        // for sanity, we're going to assume unorm8 decoding mode
190*61046927SAndroid Build Coastguard Worker        // is implied when using sRGB.
191*61046927SAndroid Build Coastguard Worker        ep0 = (ep0 << 8) | ivec4(0x80);
192*61046927SAndroid Build Coastguard Worker        ep1 = (ep1 << 8) | ivec4(0x80);
193*61046927SAndroid Build Coastguard Worker    }
194*61046927SAndroid Build Coastguard Worker    else
195*61046927SAndroid Build Coastguard Worker    {
196*61046927SAndroid Build Coastguard Worker        ep0 *= 0x101;
197*61046927SAndroid Build Coastguard Worker        ep1 *= 0x101;
198*61046927SAndroid Build Coastguard Worker    }
199*61046927SAndroid Build Coastguard Worker
200*61046927SAndroid Build Coastguard Worker    ivec4 color = (ep0 * (64 - weight) + ep1 * weight + 32) >> 6;
201*61046927SAndroid Build Coastguard Worker    return color;
202*61046927SAndroid Build Coastguard Worker}
203*61046927SAndroid Build Coastguard Worker
204*61046927SAndroid Build Coastguard Workerbvec4 bvec_or(bvec4 a, bvec4 b)
205*61046927SAndroid Build Coastguard Worker{
206*61046927SAndroid Build Coastguard Worker    return bvec4(ivec4(a) | ivec4(b));
207*61046927SAndroid Build Coastguard Worker}
208*61046927SAndroid Build Coastguard Worker
209*61046927SAndroid Build Coastguard Workeruint round_down_quantize_fp16(int color)
210*61046927SAndroid Build Coastguard Worker{
211*61046927SAndroid Build Coastguard Worker    // ASTC has a very peculiar way of converting the decoded result to FP16.
212*61046927SAndroid Build Coastguard Worker    // 0xffff -> 1.0, and for everything else we get roundDownQuantizeFP16(vec4(c) / vec4(0x10000)).
213*61046927SAndroid Build Coastguard Worker    int msb = findMSB(color);
214*61046927SAndroid Build Coastguard Worker    int shamt = msb;
215*61046927SAndroid Build Coastguard Worker    int m = ((color << 10) >> shamt) & 0x3ff;
216*61046927SAndroid Build Coastguard Worker    int e = msb - 1;
217*61046927SAndroid Build Coastguard Worker    uint decoded = color == 0xffff ? 0x3c00u : uint(e < 1 ? (color << 8) : (m | (e << 10)));
218*61046927SAndroid Build Coastguard Worker    return decoded;
219*61046927SAndroid Build Coastguard Worker}
220*61046927SAndroid Build Coastguard Worker
221*61046927SAndroid Build Coastguard Workeruvec4 round_down_quantize_fp16(ivec4 color)
222*61046927SAndroid Build Coastguard Worker{
223*61046927SAndroid Build Coastguard Worker    // ASTC has a very peculiar way of converting the decoded result to FP16.
224*61046927SAndroid Build Coastguard Worker    // 0xffff -> 1.0, and for everything else we get roundDownQuantizeFP16(vec4(c) / vec4(0x10000)).
225*61046927SAndroid Build Coastguard Worker    ivec4 msb = findMSB(color);
226*61046927SAndroid Build Coastguard Worker    ivec4 shamt = msb;
227*61046927SAndroid Build Coastguard Worker    ivec4 m = ((color << 10) >> shamt) & 0x3ff;
228*61046927SAndroid Build Coastguard Worker    ivec4 e = msb - 1;
229*61046927SAndroid Build Coastguard Worker    uvec4 decoded = uvec4(m | (e << 10));
230*61046927SAndroid Build Coastguard Worker    uvec4 denorm_decode = uvec4(color << 8);
231*61046927SAndroid Build Coastguard Worker    decoded = mix(decoded, uvec4(denorm_decode), lessThan(e, ivec4(1)));
232*61046927SAndroid Build Coastguard Worker    decoded = mix(decoded, uvec4(0x3c00), equal(color, ivec4(0xffff)));
233*61046927SAndroid Build Coastguard Worker    return decoded;
234*61046927SAndroid Build Coastguard Worker}
235*61046927SAndroid Build Coastguard Worker
236*61046927SAndroid Build Coastguard Workeruvec4 decode_fp16(ivec4 color, int decode_mode)
237*61046927SAndroid Build Coastguard Worker{
238*61046927SAndroid Build Coastguard Worker    if (decode_mode != MODE_LDR)
239*61046927SAndroid Build Coastguard Worker    {
240*61046927SAndroid Build Coastguard Worker        // Interpret the value as FP16, but with some extra fixups along the way to make the interpolation more
241*61046927SAndroid Build Coastguard Worker        // logarithmic (apparently). From spec:
242*61046927SAndroid Build Coastguard Worker        ivec4 e = color >> 11;
243*61046927SAndroid Build Coastguard Worker        ivec4 m = color & 0x7ff;
244*61046927SAndroid Build Coastguard Worker        ivec4 mt = 4 * m - 512;
245*61046927SAndroid Build Coastguard Worker        mt = mix(mt, ivec4(3 * m), lessThan(m, ivec4(512)));
246*61046927SAndroid Build Coastguard Worker        mt = mix(mt, ivec4(5 * m - 2048), greaterThanEqual(m, ivec4(1536)));
247*61046927SAndroid Build Coastguard Worker
248*61046927SAndroid Build Coastguard Worker        ivec4 decoded = (e << 10) + (mt >> 3);
249*61046927SAndroid Build Coastguard Worker        // +Inf or NaN are decoded to 0x7bff (max finite value).
250*61046927SAndroid Build Coastguard Worker        decoded = mix(decoded, ivec4(0x7bff), bvec_or(greaterThan(decoded & 0x7fff, ivec4(0x7c00)), equal(decoded, ivec4(0x7c00))));
251*61046927SAndroid Build Coastguard Worker
252*61046927SAndroid Build Coastguard Worker        if (decode_mode == MODE_HDR_LDR_ALPHA)
253*61046927SAndroid Build Coastguard Worker            decoded.a = int(round_down_quantize_fp16(color.a));
254*61046927SAndroid Build Coastguard Worker
255*61046927SAndroid Build Coastguard Worker        return uvec4(decoded);
256*61046927SAndroid Build Coastguard Worker    }
257*61046927SAndroid Build Coastguard Worker    else
258*61046927SAndroid Build Coastguard Worker    {
259*61046927SAndroid Build Coastguard Worker        return round_down_quantize_fp16(color);
260*61046927SAndroid Build Coastguard Worker    }
261*61046927SAndroid Build Coastguard Worker}
262*61046927SAndroid Build Coastguard Worker
263*61046927SAndroid Build Coastguard Workerstruct BlockMode
264*61046927SAndroid Build Coastguard Worker{
265*61046927SAndroid Build Coastguard Worker    ivec2 weight_grid_size;
266*61046927SAndroid Build Coastguard Worker    int weight_mode_index;
267*61046927SAndroid Build Coastguard Worker    int num_partitions;
268*61046927SAndroid Build Coastguard Worker    int seed;
269*61046927SAndroid Build Coastguard Worker    int cem;
270*61046927SAndroid Build Coastguard Worker    int config_bits;
271*61046927SAndroid Build Coastguard Worker    int primary_config_bits;
272*61046927SAndroid Build Coastguard Worker    bool dual_plane;
273*61046927SAndroid Build Coastguard Worker    bool void_extent;
274*61046927SAndroid Build Coastguard Worker};
275*61046927SAndroid Build Coastguard Worker
276*61046927SAndroid Build Coastguard Workerbool decode_error = false;
277*61046927SAndroid Build Coastguard Worker
278*61046927SAndroid Build Coastguard WorkerBlockMode decode_block_mode(uvec4 payload)
279*61046927SAndroid Build Coastguard Worker{
280*61046927SAndroid Build Coastguard Worker    BlockMode mode;
281*61046927SAndroid Build Coastguard Worker    mode.void_extent = (payload.x & 0x1ffu) == 0x1fcu;
282*61046927SAndroid Build Coastguard Worker    if (mode.void_extent)
283*61046927SAndroid Build Coastguard Worker        return mode;
284*61046927SAndroid Build Coastguard Worker
285*61046927SAndroid Build Coastguard Worker    mode.dual_plane = (payload.x & (1u << 10u)) != 0u;
286*61046927SAndroid Build Coastguard Worker
287*61046927SAndroid Build Coastguard Worker    uint higher = (payload.x >> 2u) & 3u;
288*61046927SAndroid Build Coastguard Worker    uint lower = payload.x & 3u;
289*61046927SAndroid Build Coastguard Worker
290*61046927SAndroid Build Coastguard Worker    if (lower != 0u)
291*61046927SAndroid Build Coastguard Worker    {
292*61046927SAndroid Build Coastguard Worker        mode.weight_mode_index = int((payload.x >> 4u) & 1u);
293*61046927SAndroid Build Coastguard Worker        mode.weight_mode_index |= int((payload.x << 1u) & 6u);
294*61046927SAndroid Build Coastguard Worker        mode.weight_mode_index |= int((payload.x >> 6u) & 8u);
295*61046927SAndroid Build Coastguard Worker
296*61046927SAndroid Build Coastguard Worker        if (higher < 2u)
297*61046927SAndroid Build Coastguard Worker        {
298*61046927SAndroid Build Coastguard Worker            mode.weight_grid_size.x = int(bitfieldExtract(payload.x, 7, 2) + 4u + 4u * higher);
299*61046927SAndroid Build Coastguard Worker            mode.weight_grid_size.y = int(bitfieldExtract(payload.x, 5, 2) + 2u);
300*61046927SAndroid Build Coastguard Worker        }
301*61046927SAndroid Build Coastguard Worker        else if (higher == 2u)
302*61046927SAndroid Build Coastguard Worker        {
303*61046927SAndroid Build Coastguard Worker            mode.weight_grid_size.x = int(bitfieldExtract(payload.x, 5, 2) + 2u);
304*61046927SAndroid Build Coastguard Worker            mode.weight_grid_size.y = int(bitfieldExtract(payload.x, 7, 2) + 8u);
305*61046927SAndroid Build Coastguard Worker        }
306*61046927SAndroid Build Coastguard Worker        else
307*61046927SAndroid Build Coastguard Worker        {
308*61046927SAndroid Build Coastguard Worker            if ((payload.x & (1u << 8u)) != 0u)
309*61046927SAndroid Build Coastguard Worker            {
310*61046927SAndroid Build Coastguard Worker                mode.weight_grid_size.x = int(bitfieldExtract(payload.x, 7, 1) + 2u);
311*61046927SAndroid Build Coastguard Worker                mode.weight_grid_size.y = int(bitfieldExtract(payload.x, 5, 2) + 2u);
312*61046927SAndroid Build Coastguard Worker            }
313*61046927SAndroid Build Coastguard Worker            else
314*61046927SAndroid Build Coastguard Worker            {
315*61046927SAndroid Build Coastguard Worker                mode.weight_grid_size.x = int(bitfieldExtract(payload.x, 5, 2) + 2u);
316*61046927SAndroid Build Coastguard Worker                mode.weight_grid_size.y = int(bitfieldExtract(payload.x, 7, 1) + 6u);
317*61046927SAndroid Build Coastguard Worker            }
318*61046927SAndroid Build Coastguard Worker        }
319*61046927SAndroid Build Coastguard Worker    }
320*61046927SAndroid Build Coastguard Worker    else
321*61046927SAndroid Build Coastguard Worker    {
322*61046927SAndroid Build Coastguard Worker        int p3 = int(bitfieldExtract(payload.x, 9, 1));
323*61046927SAndroid Build Coastguard Worker        int hi = int(bitfieldExtract(payload.x, 7, 2));
324*61046927SAndroid Build Coastguard Worker        int lo = int(bitfieldExtract(payload.x, 5, 2));
325*61046927SAndroid Build Coastguard Worker        if (hi == 0)
326*61046927SAndroid Build Coastguard Worker        {
327*61046927SAndroid Build Coastguard Worker            mode.weight_grid_size.x = 12;
328*61046927SAndroid Build Coastguard Worker            mode.weight_grid_size.y = lo + 2;
329*61046927SAndroid Build Coastguard Worker        }
330*61046927SAndroid Build Coastguard Worker        else if (hi == 1)
331*61046927SAndroid Build Coastguard Worker        {
332*61046927SAndroid Build Coastguard Worker            mode.weight_grid_size.x = lo + 2;
333*61046927SAndroid Build Coastguard Worker            mode.weight_grid_size.y = 12;
334*61046927SAndroid Build Coastguard Worker        }
335*61046927SAndroid Build Coastguard Worker        else if (hi == 2)
336*61046927SAndroid Build Coastguard Worker        {
337*61046927SAndroid Build Coastguard Worker            mode.dual_plane = false;
338*61046927SAndroid Build Coastguard Worker            p3 = 0;
339*61046927SAndroid Build Coastguard Worker            mode.weight_grid_size.x = lo + 6;
340*61046927SAndroid Build Coastguard Worker            mode.weight_grid_size.y = int(bitfieldExtract(payload.x, 9, 2) + 6u);
341*61046927SAndroid Build Coastguard Worker        }
342*61046927SAndroid Build Coastguard Worker        else
343*61046927SAndroid Build Coastguard Worker        {
344*61046927SAndroid Build Coastguard Worker            if (lo == 0)
345*61046927SAndroid Build Coastguard Worker                mode.weight_grid_size = ivec2(6, 10);
346*61046927SAndroid Build Coastguard Worker            else if (lo == 1)
347*61046927SAndroid Build Coastguard Worker                mode.weight_grid_size = ivec2(10, 6);
348*61046927SAndroid Build Coastguard Worker            else
349*61046927SAndroid Build Coastguard Worker                decode_error = true;
350*61046927SAndroid Build Coastguard Worker        }
351*61046927SAndroid Build Coastguard Worker
352*61046927SAndroid Build Coastguard Worker        int p0 = int(bitfieldExtract(payload.x, 4, 1));
353*61046927SAndroid Build Coastguard Worker        int p1 = int(bitfieldExtract(payload.x, 2, 1));
354*61046927SAndroid Build Coastguard Worker        int p2 = int(bitfieldExtract(payload.x, 3, 1));
355*61046927SAndroid Build Coastguard Worker        mode.weight_mode_index = p0 + (p1 << 1) + (p2 << 2) + (p3 << 3);
356*61046927SAndroid Build Coastguard Worker    }
357*61046927SAndroid Build Coastguard Worker
358*61046927SAndroid Build Coastguard Worker    // 11 bits for block mode.
359*61046927SAndroid Build Coastguard Worker    // 2 bits for partition select
360*61046927SAndroid Build Coastguard Worker    // If partitions > 1:
361*61046927SAndroid Build Coastguard Worker    //   4 bits CEM selector
362*61046927SAndroid Build Coastguard Worker    //   If dual_plane:
363*61046927SAndroid Build Coastguard Worker    //     2 bits of CCS
364*61046927SAndroid Build Coastguard Worker    // else:
365*61046927SAndroid Build Coastguard Worker    //   10 for partition seed
366*61046927SAndroid Build Coastguard Worker    //   2 bits for CEM main selector
367*61046927SAndroid Build Coastguard Worker    //   If CEM[1:0] = 00:
368*61046927SAndroid Build Coastguard Worker    //     4 bits for CEM extra selector if all same type.
369*61046927SAndroid Build Coastguard Worker    //   else:
370*61046927SAndroid Build Coastguard Worker    //     (1 + 2) * num_partitions if different types.
371*61046927SAndroid Build Coastguard Worker    //     First 4 bits are encoded next to CEM[1:0], otherwise, packed before weights.
372*61046927SAndroid Build Coastguard Worker    //   If dual_plane:
373*61046927SAndroid Build Coastguard Worker    //     2 bits of CCS before extra CEM bits.
374*61046927SAndroid Build Coastguard Worker    const int CONFIG_BITS_BLOCK = 11;
375*61046927SAndroid Build Coastguard Worker    const int CONFIG_BITS_PARTITION_MODE = 2;
376*61046927SAndroid Build Coastguard Worker    const int CONFIG_BITS_SEED = 10;
377*61046927SAndroid Build Coastguard Worker    const int CONFIG_BITS_PRIMARY_MULTI_CEM = 2;
378*61046927SAndroid Build Coastguard Worker    const int CONFIG_BITS_CEM = 4;
379*61046927SAndroid Build Coastguard Worker    const int CONFIG_BITS_EXTRA_CEM_PER_PARTITION = 3;
380*61046927SAndroid Build Coastguard Worker    const int CONFIG_BITS_CCS = 2;
381*61046927SAndroid Build Coastguard Worker
382*61046927SAndroid Build Coastguard Worker    mode.num_partitions = int(bitfieldExtract(payload.x, CONFIG_BITS_BLOCK, CONFIG_BITS_PARTITION_MODE)) + 1;
383*61046927SAndroid Build Coastguard Worker
384*61046927SAndroid Build Coastguard Worker    if (mode.num_partitions > 1)
385*61046927SAndroid Build Coastguard Worker    {
386*61046927SAndroid Build Coastguard Worker        mode.seed = int(bitfieldExtract(payload.x, CONFIG_BITS_BLOCK + CONFIG_BITS_PARTITION_MODE, CONFIG_BITS_SEED));
387*61046927SAndroid Build Coastguard Worker        mode.cem = int(bitfieldExtract(payload.x, CONFIG_BITS_BLOCK + CONFIG_BITS_PARTITION_MODE + CONFIG_BITS_SEED,
388*61046927SAndroid Build Coastguard Worker                                       CONFIG_BITS_PRIMARY_MULTI_CEM + CONFIG_BITS_CEM));
389*61046927SAndroid Build Coastguard Worker    }
390*61046927SAndroid Build Coastguard Worker    else
391*61046927SAndroid Build Coastguard Worker        mode.cem = int(bitfieldExtract(payload.x, CONFIG_BITS_BLOCK + CONFIG_BITS_PARTITION_MODE, CONFIG_BITS_CEM));
392*61046927SAndroid Build Coastguard Worker
393*61046927SAndroid Build Coastguard Worker    int config_bits;
394*61046927SAndroid Build Coastguard Worker    if (mode.num_partitions > 1)
395*61046927SAndroid Build Coastguard Worker    {
396*61046927SAndroid Build Coastguard Worker        bool single_cem = (mode.cem & 3) == 0;
397*61046927SAndroid Build Coastguard Worker        if (single_cem)
398*61046927SAndroid Build Coastguard Worker        {
399*61046927SAndroid Build Coastguard Worker            config_bits = CONFIG_BITS_BLOCK + CONFIG_BITS_PARTITION_MODE +
400*61046927SAndroid Build Coastguard Worker                          CONFIG_BITS_SEED + CONFIG_BITS_PRIMARY_MULTI_CEM + CONFIG_BITS_CEM;
401*61046927SAndroid Build Coastguard Worker        }
402*61046927SAndroid Build Coastguard Worker        else
403*61046927SAndroid Build Coastguard Worker        {
404*61046927SAndroid Build Coastguard Worker            config_bits = CONFIG_BITS_BLOCK + CONFIG_BITS_PARTITION_MODE +
405*61046927SAndroid Build Coastguard Worker                          CONFIG_BITS_SEED + CONFIG_BITS_PRIMARY_MULTI_CEM +
406*61046927SAndroid Build Coastguard Worker                          CONFIG_BITS_EXTRA_CEM_PER_PARTITION * mode.num_partitions;
407*61046927SAndroid Build Coastguard Worker        }
408*61046927SAndroid Build Coastguard Worker    }
409*61046927SAndroid Build Coastguard Worker    else
410*61046927SAndroid Build Coastguard Worker    {
411*61046927SAndroid Build Coastguard Worker        config_bits = CONFIG_BITS_BLOCK + CONFIG_BITS_PARTITION_MODE + CONFIG_BITS_CEM;
412*61046927SAndroid Build Coastguard Worker    }
413*61046927SAndroid Build Coastguard Worker
414*61046927SAndroid Build Coastguard Worker    // Other config bits are packed before the weights.
415*61046927SAndroid Build Coastguard Worker    int primary_config_bits;
416*61046927SAndroid Build Coastguard Worker    if (mode.num_partitions > 1)
417*61046927SAndroid Build Coastguard Worker    {
418*61046927SAndroid Build Coastguard Worker        primary_config_bits = CONFIG_BITS_BLOCK + CONFIG_BITS_PARTITION_MODE + CONFIG_BITS_SEED +
419*61046927SAndroid Build Coastguard Worker                              CONFIG_BITS_PRIMARY_MULTI_CEM + CONFIG_BITS_CEM;
420*61046927SAndroid Build Coastguard Worker    }
421*61046927SAndroid Build Coastguard Worker    else
422*61046927SAndroid Build Coastguard Worker        primary_config_bits = config_bits;
423*61046927SAndroid Build Coastguard Worker
424*61046927SAndroid Build Coastguard Worker    if (mode.dual_plane)
425*61046927SAndroid Build Coastguard Worker        config_bits += CONFIG_BITS_CCS;
426*61046927SAndroid Build Coastguard Worker
427*61046927SAndroid Build Coastguard Worker    // This is not allowed.
428*61046927SAndroid Build Coastguard Worker    if (any(greaterThan(mode.weight_grid_size, ivec2(gl_WorkGroupSize.xy))))
429*61046927SAndroid Build Coastguard Worker        decode_error = true;
430*61046927SAndroid Build Coastguard Worker    if (mode.dual_plane && mode.num_partitions > 3)
431*61046927SAndroid Build Coastguard Worker        decode_error = true;
432*61046927SAndroid Build Coastguard Worker
433*61046927SAndroid Build Coastguard Worker    mode.config_bits = config_bits;
434*61046927SAndroid Build Coastguard Worker    mode.primary_config_bits = primary_config_bits;
435*61046927SAndroid Build Coastguard Worker    return mode;
436*61046927SAndroid Build Coastguard Worker}
437*61046927SAndroid Build Coastguard Worker
438*61046927SAndroid Build Coastguard Workerint idiv3_floor(int v)
439*61046927SAndroid Build Coastguard Worker{
440*61046927SAndroid Build Coastguard Worker    return (v * 0x5556) >> 16;
441*61046927SAndroid Build Coastguard Worker}
442*61046927SAndroid Build Coastguard Worker
443*61046927SAndroid Build Coastguard Workerint idiv3_ceil(int v)
444*61046927SAndroid Build Coastguard Worker{
445*61046927SAndroid Build Coastguard Worker    return idiv3_floor(v + 2);
446*61046927SAndroid Build Coastguard Worker}
447*61046927SAndroid Build Coastguard Worker
448*61046927SAndroid Build Coastguard Workerint idiv5_floor(int v)
449*61046927SAndroid Build Coastguard Worker{
450*61046927SAndroid Build Coastguard Worker    return (v * 0x3334) >> 16;
451*61046927SAndroid Build Coastguard Worker}
452*61046927SAndroid Build Coastguard Worker
453*61046927SAndroid Build Coastguard Workerint idiv5_ceil(int v)
454*61046927SAndroid Build Coastguard Worker{
455*61046927SAndroid Build Coastguard Worker    return idiv5_floor(v + 4);
456*61046927SAndroid Build Coastguard Worker}
457*61046927SAndroid Build Coastguard Worker
458*61046927SAndroid Build Coastguard Workeruvec4 build_bitmask(int bits)
459*61046927SAndroid Build Coastguard Worker{
460*61046927SAndroid Build Coastguard Worker    ivec4 num_bits = ivec4(bits, bits - 32, bits - 64, bits - 96);
461*61046927SAndroid Build Coastguard Worker    uvec4 mask = uvec4(1) << clamp(num_bits, ivec4(0), ivec4(31));
462*61046927SAndroid Build Coastguard Worker    mask--;
463*61046927SAndroid Build Coastguard Worker    mask = mix(mask, uvec4(0xffffffffu), greaterThanEqual(uvec4(bits), uvec4(32, 64, 96, 128)));
464*61046927SAndroid Build Coastguard Worker    return mask;
465*61046927SAndroid Build Coastguard Worker}
466*61046927SAndroid Build Coastguard Worker
467*61046927SAndroid Build Coastguard Workerint decode_integer_sequence(uvec4 payload, int start_bit, int index, ivec3 quant)
468*61046927SAndroid Build Coastguard Worker{
469*61046927SAndroid Build Coastguard Worker    int ret;
470*61046927SAndroid Build Coastguard Worker    if (quant.y != 0)
471*61046927SAndroid Build Coastguard Worker    {
472*61046927SAndroid Build Coastguard Worker        // Trit-decoding.
473*61046927SAndroid Build Coastguard Worker        int block = idiv5_floor(index);
474*61046927SAndroid Build Coastguard Worker        int offset = index - block * 5;
475*61046927SAndroid Build Coastguard Worker        start_bit += block * (5 * quant.x + 8);
476*61046927SAndroid Build Coastguard Worker
477*61046927SAndroid Build Coastguard Worker        int t0_t1_offset = start_bit + (quant.x * 1 + 0);
478*61046927SAndroid Build Coastguard Worker        int t2_t3_offset = start_bit + (quant.x * 2 + 2);
479*61046927SAndroid Build Coastguard Worker        int t4_offset    = start_bit + (quant.x * 3 + 4);
480*61046927SAndroid Build Coastguard Worker        int t5_t6_offset = start_bit + (quant.x * 4 + 5);
481*61046927SAndroid Build Coastguard Worker        int t7_offset    = start_bit + (quant.x * 5 + 7);
482*61046927SAndroid Build Coastguard Worker
483*61046927SAndroid Build Coastguard Worker        int t = (extract_bits(payload, t0_t1_offset, 2) << 0) |
484*61046927SAndroid Build Coastguard Worker                (extract_bits(payload, t2_t3_offset, 2) << 2) |
485*61046927SAndroid Build Coastguard Worker                (extract_bits(payload, t4_offset, 1) << 4) |
486*61046927SAndroid Build Coastguard Worker                (extract_bits(payload, t5_t6_offset, 2) << 5) |
487*61046927SAndroid Build Coastguard Worker                (extract_bits(payload, t7_offset, 1) << 7);
488*61046927SAndroid Build Coastguard Worker
489*61046927SAndroid Build Coastguard Worker        t = int(texelFetch(LUTTritQuintDecode, t).x);
490*61046927SAndroid Build Coastguard Worker        t = (t >> (3 * offset)) & 7;
491*61046927SAndroid Build Coastguard Worker
492*61046927SAndroid Build Coastguard Worker        int m_offset = offset * quant.x;
493*61046927SAndroid Build Coastguard Worker        m_offset += idiv5_ceil(offset * 8);
494*61046927SAndroid Build Coastguard Worker
495*61046927SAndroid Build Coastguard Worker        if (quant.x != 0)
496*61046927SAndroid Build Coastguard Worker        {
497*61046927SAndroid Build Coastguard Worker            int m = extract_bits(payload, m_offset + start_bit, quant.x);
498*61046927SAndroid Build Coastguard Worker            ret = (t << quant.x) | m;
499*61046927SAndroid Build Coastguard Worker        }
500*61046927SAndroid Build Coastguard Worker        else
501*61046927SAndroid Build Coastguard Worker            ret = t;
502*61046927SAndroid Build Coastguard Worker    }
503*61046927SAndroid Build Coastguard Worker    else if (quant.z != 0)
504*61046927SAndroid Build Coastguard Worker    {
505*61046927SAndroid Build Coastguard Worker        // Quint-decoding
506*61046927SAndroid Build Coastguard Worker        int block = idiv3_floor(index);
507*61046927SAndroid Build Coastguard Worker        int offset = index - block * 3;
508*61046927SAndroid Build Coastguard Worker        start_bit += block * (3 * quant.x + 7);
509*61046927SAndroid Build Coastguard Worker
510*61046927SAndroid Build Coastguard Worker        int q0_q1_q2_offset = start_bit + (quant.x * 1 + 0);
511*61046927SAndroid Build Coastguard Worker        int q3_q4_offset    = start_bit + (quant.x * 2 + 3);
512*61046927SAndroid Build Coastguard Worker        int q5_q6_offset    = start_bit + (quant.x * 3 + 5);
513*61046927SAndroid Build Coastguard Worker
514*61046927SAndroid Build Coastguard Worker        int q = (extract_bits(payload, q0_q1_q2_offset, 3) << 0) |
515*61046927SAndroid Build Coastguard Worker                (extract_bits(payload, q3_q4_offset, 2) << 3) |
516*61046927SAndroid Build Coastguard Worker                (extract_bits(payload, q5_q6_offset, 2) << 5);
517*61046927SAndroid Build Coastguard Worker
518*61046927SAndroid Build Coastguard Worker        q = int(texelFetch(LUTTritQuintDecode, 256 + q).x);
519*61046927SAndroid Build Coastguard Worker        q = (q >> (3 * offset)) & 7;
520*61046927SAndroid Build Coastguard Worker
521*61046927SAndroid Build Coastguard Worker        int m_offset = offset * quant.x;
522*61046927SAndroid Build Coastguard Worker        m_offset += idiv3_ceil(offset * 7);
523*61046927SAndroid Build Coastguard Worker
524*61046927SAndroid Build Coastguard Worker        if (quant.x != 0)
525*61046927SAndroid Build Coastguard Worker        {
526*61046927SAndroid Build Coastguard Worker            int m = extract_bits(payload, m_offset + start_bit, quant.x);
527*61046927SAndroid Build Coastguard Worker            ret = (q << quant.x) | m;
528*61046927SAndroid Build Coastguard Worker        }
529*61046927SAndroid Build Coastguard Worker        else
530*61046927SAndroid Build Coastguard Worker            ret = q;
531*61046927SAndroid Build Coastguard Worker    }
532*61046927SAndroid Build Coastguard Worker    else
533*61046927SAndroid Build Coastguard Worker    {
534*61046927SAndroid Build Coastguard Worker        int bit = index * quant.x;
535*61046927SAndroid Build Coastguard Worker        ret = extract_bits(payload, start_bit + bit, quant.x);
536*61046927SAndroid Build Coastguard Worker    }
537*61046927SAndroid Build Coastguard Worker    return ret;
538*61046927SAndroid Build Coastguard Worker}
539*61046927SAndroid Build Coastguard Worker
540*61046927SAndroid Build Coastguard Workerivec2 normalize_coord(ivec2 pixel_coord)
541*61046927SAndroid Build Coastguard Worker{
542*61046927SAndroid Build Coastguard Worker    ivec2 D = ivec2((vec2((1024 + ivec2(gl_WorkGroupSize.xy >> 1u))) + 0.5) / vec2(gl_WorkGroupSize.xy - 1u));
543*61046927SAndroid Build Coastguard Worker    ivec2 c = D * pixel_coord;
544*61046927SAndroid Build Coastguard Worker    return c;
545*61046927SAndroid Build Coastguard Worker}
546*61046927SAndroid Build Coastguard Worker
547*61046927SAndroid Build Coastguard Workerint decode_weight(uvec4 payload, int weight_index, ivec4 quant)
548*61046927SAndroid Build Coastguard Worker{
549*61046927SAndroid Build Coastguard Worker    int primary_weight = decode_integer_sequence(payload, 0, weight_index, quant.xyz);
550*61046927SAndroid Build Coastguard Worker    primary_weight = int(texelFetch(LUTWeightUnquantize, primary_weight + quant.w).x);
551*61046927SAndroid Build Coastguard Worker    return primary_weight;
552*61046927SAndroid Build Coastguard Worker}
553*61046927SAndroid Build Coastguard Worker
554*61046927SAndroid Build Coastguard Workerint decode_weight_bilinear(uvec4 payload, ivec2 coord, int weight_resolution,
555*61046927SAndroid Build Coastguard Worker                           int stride, int offset, ivec2 fractional, ivec4 quant)
556*61046927SAndroid Build Coastguard Worker{
557*61046927SAndroid Build Coastguard Worker    int index = coord.y * weight_resolution + coord.x;
558*61046927SAndroid Build Coastguard Worker    int p00 = decode_weight(payload, stride * index + offset, quant);
559*61046927SAndroid Build Coastguard Worker    int p10, p01, p11;
560*61046927SAndroid Build Coastguard Worker
561*61046927SAndroid Build Coastguard Worker    if (fractional.x != 0)
562*61046927SAndroid Build Coastguard Worker        p10 = decode_weight(payload, stride * (index + 1) + offset, quant);
563*61046927SAndroid Build Coastguard Worker    else
564*61046927SAndroid Build Coastguard Worker        p10 = p00;
565*61046927SAndroid Build Coastguard Worker
566*61046927SAndroid Build Coastguard Worker    if (fractional.y != 0)
567*61046927SAndroid Build Coastguard Worker    {
568*61046927SAndroid Build Coastguard Worker        p01 = decode_weight(payload, stride * (index + weight_resolution) + offset, quant);
569*61046927SAndroid Build Coastguard Worker        if (fractional.x != 0)
570*61046927SAndroid Build Coastguard Worker            p11 = decode_weight(payload, stride * (index + weight_resolution + 1) + offset, quant);
571*61046927SAndroid Build Coastguard Worker        else
572*61046927SAndroid Build Coastguard Worker            p11 = p01;
573*61046927SAndroid Build Coastguard Worker    }
574*61046927SAndroid Build Coastguard Worker    else
575*61046927SAndroid Build Coastguard Worker    {
576*61046927SAndroid Build Coastguard Worker        p01 = p00;
577*61046927SAndroid Build Coastguard Worker        p11 = p10;
578*61046927SAndroid Build Coastguard Worker    }
579*61046927SAndroid Build Coastguard Worker
580*61046927SAndroid Build Coastguard Worker    int w11 = (fractional.x * fractional.y + 8) >> 4;
581*61046927SAndroid Build Coastguard Worker    int w10 = fractional.x - w11;
582*61046927SAndroid Build Coastguard Worker    int w01 = fractional.y - w11;
583*61046927SAndroid Build Coastguard Worker    int w00 = 16 - fractional.x - fractional.y + w11;
584*61046927SAndroid Build Coastguard Worker    return (p00 * w00 + p10 * w10 + p01 * w01 + p11 * w11 + 8) >> 4;
585*61046927SAndroid Build Coastguard Worker}
586*61046927SAndroid Build Coastguard Worker
587*61046927SAndroid Build Coastguard Workerivec4 decode_weights(uvec4 payload, BlockMode mode, ivec2 normalized_pixel, out int weight_cost_bits)
588*61046927SAndroid Build Coastguard Worker{
589*61046927SAndroid Build Coastguard Worker    ivec4 quant = ivec4(texelFetch(LUTWeightQuantizer, mode.weight_mode_index));
590*61046927SAndroid Build Coastguard Worker    int num_weights = mode.weight_grid_size.x * mode.weight_grid_size.y;
591*61046927SAndroid Build Coastguard Worker    num_weights <<= int(mode.dual_plane);
592*61046927SAndroid Build Coastguard Worker    weight_cost_bits =
593*61046927SAndroid Build Coastguard Worker        quant.x * num_weights +
594*61046927SAndroid Build Coastguard Worker        idiv5_ceil(num_weights * 8 * quant.y) +
595*61046927SAndroid Build Coastguard Worker        idiv3_ceil(num_weights * 7 * quant.z);
596*61046927SAndroid Build Coastguard Worker
597*61046927SAndroid Build Coastguard Worker    // Decoders must deal with error conditions and return the correct error color.
598*61046927SAndroid Build Coastguard Worker    if (weight_cost_bits < 24 || weight_cost_bits > 96 || num_weights > 64)
599*61046927SAndroid Build Coastguard Worker    {
600*61046927SAndroid Build Coastguard Worker        decode_error = true;
601*61046927SAndroid Build Coastguard Worker        return ivec4(0);
602*61046927SAndroid Build Coastguard Worker    }
603*61046927SAndroid Build Coastguard Worker
604*61046927SAndroid Build Coastguard Worker    int ccs;
605*61046927SAndroid Build Coastguard Worker    if (mode.dual_plane)
606*61046927SAndroid Build Coastguard Worker    {
607*61046927SAndroid Build Coastguard Worker        int extra_cem_bits = 0;
608*61046927SAndroid Build Coastguard Worker        if ((mode.cem & 3) != 0)
609*61046927SAndroid Build Coastguard Worker            extra_cem_bits = max(mode.num_partitions * 3 - 4, 0);
610*61046927SAndroid Build Coastguard Worker        ccs = extract_bits(payload, 126 - weight_cost_bits - extra_cem_bits, 2);
611*61046927SAndroid Build Coastguard Worker    }
612*61046927SAndroid Build Coastguard Worker
613*61046927SAndroid Build Coastguard Worker    payload = bitfieldReverse(payload);
614*61046927SAndroid Build Coastguard Worker    payload = payload.wzyx;
615*61046927SAndroid Build Coastguard Worker    payload &= build_bitmask(weight_cost_bits);
616*61046927SAndroid Build Coastguard Worker
617*61046927SAndroid Build Coastguard Worker    // Scale the normalized coordinate to weight grid.
618*61046927SAndroid Build Coastguard Worker    ivec2 weight_pixel_fixed_point = (normalized_pixel * (mode.weight_grid_size - 1) + 32) >> 6;
619*61046927SAndroid Build Coastguard Worker    ivec2 weight_pixel = weight_pixel_fixed_point >> 4;
620*61046927SAndroid Build Coastguard Worker    ivec2 weight_pixel_fractional = weight_pixel_fixed_point & 0xf;
621*61046927SAndroid Build Coastguard Worker
622*61046927SAndroid Build Coastguard Worker    ivec4 ret;
623*61046927SAndroid Build Coastguard Worker    int primary_weight = decode_weight_bilinear(payload, weight_pixel, mode.weight_grid_size.x,
624*61046927SAndroid Build Coastguard Worker                                                1 << int(mode.dual_plane), 0,
625*61046927SAndroid Build Coastguard Worker                                                weight_pixel_fractional, quant);
626*61046927SAndroid Build Coastguard Worker    if (mode.dual_plane)
627*61046927SAndroid Build Coastguard Worker    {
628*61046927SAndroid Build Coastguard Worker        int secondary_weight = decode_weight_bilinear(payload, weight_pixel, mode.weight_grid_size.x,
629*61046927SAndroid Build Coastguard Worker                                                      2, 1,
630*61046927SAndroid Build Coastguard Worker                                                      weight_pixel_fractional, quant);
631*61046927SAndroid Build Coastguard Worker        ret = mix(ivec4(primary_weight), ivec4(secondary_weight), equal(ivec4(ccs), ivec4(0, 1, 2, 3)));
632*61046927SAndroid Build Coastguard Worker    }
633*61046927SAndroid Build Coastguard Worker    else
634*61046927SAndroid Build Coastguard Worker        ret = ivec4(primary_weight);
635*61046927SAndroid Build Coastguard Worker
636*61046927SAndroid Build Coastguard Worker    return ret;
637*61046927SAndroid Build Coastguard Worker}
638*61046927SAndroid Build Coastguard Worker
639*61046927SAndroid Build Coastguard Workervoid decode_endpoint_ldr_luma_direct(out ivec4 ep0, out ivec4 ep1,
640*61046927SAndroid Build Coastguard Worker        int v0, int v1)
641*61046927SAndroid Build Coastguard Worker{
642*61046927SAndroid Build Coastguard Worker    ep0 = ivec4(ivec3(v0), 0xff);
643*61046927SAndroid Build Coastguard Worker    ep1 = ivec4(ivec3(v1), 0xff);
644*61046927SAndroid Build Coastguard Worker}
645*61046927SAndroid Build Coastguard Worker
646*61046927SAndroid Build Coastguard Workervoid decode_endpoint_hdr_luma_direct(out ivec4 ep0, out ivec4 ep1,
647*61046927SAndroid Build Coastguard Worker        int v0, int v1)
648*61046927SAndroid Build Coastguard Worker{
649*61046927SAndroid Build Coastguard Worker    int y0, y1;
650*61046927SAndroid Build Coastguard Worker    if (v1 >= v0)
651*61046927SAndroid Build Coastguard Worker    {
652*61046927SAndroid Build Coastguard Worker        y0 = v0 << 4;
653*61046927SAndroid Build Coastguard Worker        y1 = v1 << 4;
654*61046927SAndroid Build Coastguard Worker    }
655*61046927SAndroid Build Coastguard Worker    else
656*61046927SAndroid Build Coastguard Worker    {
657*61046927SAndroid Build Coastguard Worker        y0 = (v1 << 4) + 8;
658*61046927SAndroid Build Coastguard Worker        y1 = (v0 << 4) - 8;
659*61046927SAndroid Build Coastguard Worker    }
660*61046927SAndroid Build Coastguard Worker
661*61046927SAndroid Build Coastguard Worker    ep0 = ivec4(ivec3(y0), 0x780);
662*61046927SAndroid Build Coastguard Worker    ep1 = ivec4(ivec3(y1), 0x780);
663*61046927SAndroid Build Coastguard Worker}
664*61046927SAndroid Build Coastguard Worker
665*61046927SAndroid Build Coastguard Workervoid decode_endpoint_hdr_luma_direct_small_range(out ivec4 ep0, out ivec4 ep1,
666*61046927SAndroid Build Coastguard Worker        int v0, int v1)
667*61046927SAndroid Build Coastguard Worker{
668*61046927SAndroid Build Coastguard Worker    int y0, y1, d;
669*61046927SAndroid Build Coastguard Worker
670*61046927SAndroid Build Coastguard Worker    if ((v0 & 0x80) != 0)
671*61046927SAndroid Build Coastguard Worker    {
672*61046927SAndroid Build Coastguard Worker        y0 = ((v1 & 0xe0) << 4) | ((v0 & 0x7f) << 2);
673*61046927SAndroid Build Coastguard Worker        d = (v1 & 0x1f) << 2;
674*61046927SAndroid Build Coastguard Worker    }
675*61046927SAndroid Build Coastguard Worker    else
676*61046927SAndroid Build Coastguard Worker    {
677*61046927SAndroid Build Coastguard Worker        y0 = ((v1 & 0xf0) << 4) | ((v0 & 0x7f) << 1);
678*61046927SAndroid Build Coastguard Worker        d = (v1 & 0x0f)  << 1;
679*61046927SAndroid Build Coastguard Worker    }
680*61046927SAndroid Build Coastguard Worker
681*61046927SAndroid Build Coastguard Worker    y1 = min(y0 + d, 0xfff);
682*61046927SAndroid Build Coastguard Worker
683*61046927SAndroid Build Coastguard Worker    ep0 = ivec4(ivec3(y0), 0x780);
684*61046927SAndroid Build Coastguard Worker    ep1 = ivec4(ivec3(y1), 0x780);
685*61046927SAndroid Build Coastguard Worker}
686*61046927SAndroid Build Coastguard Worker
687*61046927SAndroid Build Coastguard Workervoid decode_endpoint_ldr_luma_base_offset(out ivec4 ep0, out ivec4 ep1,
688*61046927SAndroid Build Coastguard Worker        int v0, int v1)
689*61046927SAndroid Build Coastguard Worker{
690*61046927SAndroid Build Coastguard Worker    int l0 = (v0 >> 2) | (v1 & 0xc0);
691*61046927SAndroid Build Coastguard Worker    int l1 = l0 + (v1 & 0x3f);
692*61046927SAndroid Build Coastguard Worker    l1 = min(l1, 0xff);
693*61046927SAndroid Build Coastguard Worker    ep0 = ivec4(ivec3(l0), 0xff);
694*61046927SAndroid Build Coastguard Worker    ep1 = ivec4(ivec3(l1), 0xff);
695*61046927SAndroid Build Coastguard Worker}
696*61046927SAndroid Build Coastguard Worker
697*61046927SAndroid Build Coastguard Workervoid decode_endpoint_ldr_luma_alpha_direct(out ivec4 ep0, out ivec4 ep1,
698*61046927SAndroid Build Coastguard Worker    int v0, int v1, int v2, int v3)
699*61046927SAndroid Build Coastguard Worker{
700*61046927SAndroid Build Coastguard Worker    ep0 = ivec4(ivec3(v0), v2);
701*61046927SAndroid Build Coastguard Worker    ep1 = ivec4(ivec3(v1), v3);
702*61046927SAndroid Build Coastguard Worker}
703*61046927SAndroid Build Coastguard Worker
704*61046927SAndroid Build Coastguard Workerivec4 blue_contract(int r, int g, int b, int a)
705*61046927SAndroid Build Coastguard Worker{
706*61046927SAndroid Build Coastguard Worker    ivec4 ret;
707*61046927SAndroid Build Coastguard Worker    ret.r = (r + b) >> 1;
708*61046927SAndroid Build Coastguard Worker    ret.g = (g + b) >> 1;
709*61046927SAndroid Build Coastguard Worker    ret.b = b;
710*61046927SAndroid Build Coastguard Worker    ret.a = a;
711*61046927SAndroid Build Coastguard Worker    return ret;
712*61046927SAndroid Build Coastguard Worker}
713*61046927SAndroid Build Coastguard Worker
714*61046927SAndroid Build Coastguard Workervoid bit_transfer_signed(inout int a, inout int b)
715*61046927SAndroid Build Coastguard Worker{
716*61046927SAndroid Build Coastguard Worker    b >>= 1;
717*61046927SAndroid Build Coastguard Worker    b |= a & 0x80;
718*61046927SAndroid Build Coastguard Worker    a >>= 1;
719*61046927SAndroid Build Coastguard Worker    a &= 0x3f;
720*61046927SAndroid Build Coastguard Worker    a = bitfieldExtract(a, 0, 6);
721*61046927SAndroid Build Coastguard Worker}
722*61046927SAndroid Build Coastguard Worker
723*61046927SAndroid Build Coastguard Workervoid decode_endpoint_ldr_luma_alpha_base_offset(out ivec4 ep0, out ivec4 ep1,
724*61046927SAndroid Build Coastguard Worker    int v0, int v1, int v2, int v3)
725*61046927SAndroid Build Coastguard Worker{
726*61046927SAndroid Build Coastguard Worker    bit_transfer_signed(v1, v0);
727*61046927SAndroid Build Coastguard Worker    bit_transfer_signed(v3, v2);
728*61046927SAndroid Build Coastguard Worker    int v0_v1 = clamp(v0 + v1, 0, 0xff);
729*61046927SAndroid Build Coastguard Worker    int v2_v3 = clamp(v2 + v3, 0, 0xff);
730*61046927SAndroid Build Coastguard Worker    v0 = clamp(v0, 0, 0xff);
731*61046927SAndroid Build Coastguard Worker    v2 = clamp(v2, 0, 0xff);
732*61046927SAndroid Build Coastguard Worker    ep0 = ivec4(ivec3(v0), v2);
733*61046927SAndroid Build Coastguard Worker    ep1 = ivec4(ivec3(v0_v1), v2_v3);
734*61046927SAndroid Build Coastguard Worker}
735*61046927SAndroid Build Coastguard Worker
736*61046927SAndroid Build Coastguard Workervoid decode_endpoint_ldr_rgb_base_scale(out ivec4 ep0, out ivec4 ep1,
737*61046927SAndroid Build Coastguard Worker        int v0, int v1, int v2, int v3)
738*61046927SAndroid Build Coastguard Worker{
739*61046927SAndroid Build Coastguard Worker    ep0 = ivec4((ivec3(v0, v1, v2) * v3) >> 8, 0xff);
740*61046927SAndroid Build Coastguard Worker    ep1 = ivec4(v0, v1, v2, 0xff);
741*61046927SAndroid Build Coastguard Worker}
742*61046927SAndroid Build Coastguard Worker
743*61046927SAndroid Build Coastguard Workervoid decode_endpoint_ldr_rgb_base_scale_two_a(out ivec4 ep0, out ivec4 ep1,
744*61046927SAndroid Build Coastguard Worker        int v0, int v1, int v2, int v3, int v4, int v5)
745*61046927SAndroid Build Coastguard Worker{
746*61046927SAndroid Build Coastguard Worker    ep0 = ivec4((ivec3(v0, v1, v2) * v3) >> 8, v4);
747*61046927SAndroid Build Coastguard Worker    ep1 = ivec4(v0, v1, v2, v5);
748*61046927SAndroid Build Coastguard Worker}
749*61046927SAndroid Build Coastguard Worker
750*61046927SAndroid Build Coastguard Workervoid decode_endpoint_ldr_rgb_direct(out ivec4 ep0, out ivec4 ep1,
751*61046927SAndroid Build Coastguard Worker        int v0, int v1, int v2, int v3, int v4, int v5)
752*61046927SAndroid Build Coastguard Worker{
753*61046927SAndroid Build Coastguard Worker    int s0 = v0 + v2 + v4;
754*61046927SAndroid Build Coastguard Worker    int s1 = v1 + v3 + v5;
755*61046927SAndroid Build Coastguard Worker    if (s1 >= s0)
756*61046927SAndroid Build Coastguard Worker    {
757*61046927SAndroid Build Coastguard Worker        ep0 = ivec4(v0, v2, v4, 0xff);
758*61046927SAndroid Build Coastguard Worker        ep1 = ivec4(v1, v3, v5, 0xff);
759*61046927SAndroid Build Coastguard Worker    }
760*61046927SAndroid Build Coastguard Worker    else
761*61046927SAndroid Build Coastguard Worker    {
762*61046927SAndroid Build Coastguard Worker        ep0 = blue_contract(v1, v3, v5, 0xff);
763*61046927SAndroid Build Coastguard Worker        ep1 = blue_contract(v0, v2, v4, 0xff);
764*61046927SAndroid Build Coastguard Worker    }
765*61046927SAndroid Build Coastguard Worker}
766*61046927SAndroid Build Coastguard Worker
767*61046927SAndroid Build Coastguard Workervoid decode_endpoint_hdr_rgb_scale(out ivec4 ep0, out ivec4 ep1,
768*61046927SAndroid Build Coastguard Worker    int v0, int v1, int v2, int v3)
769*61046927SAndroid Build Coastguard Worker{
770*61046927SAndroid Build Coastguard Worker    // Mind-numbing weird format, just copy from spec ...
771*61046927SAndroid Build Coastguard Worker    int mode_value = ((v0 & 0xc0) >> 6) | ((v1 & 0x80) >> 5) | ((v2 & 0x80) >> 4);
772*61046927SAndroid Build Coastguard Worker    int major_component;
773*61046927SAndroid Build Coastguard Worker    int mode;
774*61046927SAndroid Build Coastguard Worker
775*61046927SAndroid Build Coastguard Worker    if ((mode_value & 0xc) != 0xc)
776*61046927SAndroid Build Coastguard Worker    {
777*61046927SAndroid Build Coastguard Worker        major_component = mode_value >> 2;
778*61046927SAndroid Build Coastguard Worker        mode = mode_value & 3;
779*61046927SAndroid Build Coastguard Worker    }
780*61046927SAndroid Build Coastguard Worker    else if (mode_value != 0xf)
781*61046927SAndroid Build Coastguard Worker    {
782*61046927SAndroid Build Coastguard Worker        major_component = mode_value & 3;
783*61046927SAndroid Build Coastguard Worker        mode = 4;
784*61046927SAndroid Build Coastguard Worker    }
785*61046927SAndroid Build Coastguard Worker    else
786*61046927SAndroid Build Coastguard Worker    {
787*61046927SAndroid Build Coastguard Worker        major_component = 0;
788*61046927SAndroid Build Coastguard Worker        mode = 5;
789*61046927SAndroid Build Coastguard Worker    }
790*61046927SAndroid Build Coastguard Worker
791*61046927SAndroid Build Coastguard Worker    int red = v0 & 0x3f;
792*61046927SAndroid Build Coastguard Worker    int green = v1 & 0x1f;
793*61046927SAndroid Build Coastguard Worker    int blue = v2 & 0x1f;
794*61046927SAndroid Build Coastguard Worker    int scale = v3 & 0x1f;
795*61046927SAndroid Build Coastguard Worker
796*61046927SAndroid Build Coastguard Worker    int x0 = (v1 >> 6) & 1;
797*61046927SAndroid Build Coastguard Worker    int x1 = (v1 >> 5) & 1;
798*61046927SAndroid Build Coastguard Worker    int x2 = (v2 >> 6) & 1;
799*61046927SAndroid Build Coastguard Worker    int x3 = (v2 >> 5) & 1;
800*61046927SAndroid Build Coastguard Worker    int x4 = (v3 >> 7) & 1;
801*61046927SAndroid Build Coastguard Worker    int x5 = (v3 >> 6) & 1;
802*61046927SAndroid Build Coastguard Worker    int x6 = (v3 >> 5) & 1;
803*61046927SAndroid Build Coastguard Worker
804*61046927SAndroid Build Coastguard Worker    int ohm = 1 << mode;
805*61046927SAndroid Build Coastguard Worker    if ((ohm & 0x30) != 0) green |= x0 << 6;
806*61046927SAndroid Build Coastguard Worker    if ((ohm & 0x3a) != 0) green |= x1 << 5;
807*61046927SAndroid Build Coastguard Worker    if ((ohm & 0x30) != 0) blue |= x2 << 6;
808*61046927SAndroid Build Coastguard Worker    if ((ohm & 0x3a) != 0) blue |= x3 << 5;
809*61046927SAndroid Build Coastguard Worker    if ((ohm & 0x3d) != 0) scale |= x6 << 5;
810*61046927SAndroid Build Coastguard Worker    if ((ohm & 0x2d) != 0) scale |= x5 << 6;
811*61046927SAndroid Build Coastguard Worker    if ((ohm & 0x04) != 0) scale |= x4 << 7;
812*61046927SAndroid Build Coastguard Worker    if ((ohm & 0x3b) != 0) red |= x4 << 6;
813*61046927SAndroid Build Coastguard Worker    if ((ohm & 0x04) != 0) red |= x3 << 6;
814*61046927SAndroid Build Coastguard Worker    if ((ohm & 0x10) != 0) red |= x5 << 7;
815*61046927SAndroid Build Coastguard Worker    if ((ohm & 0x0f) != 0) red |= x2 << 7;
816*61046927SAndroid Build Coastguard Worker    if ((ohm & 0x05) != 0) red |= x1 << 8;
817*61046927SAndroid Build Coastguard Worker    if ((ohm & 0x0a) != 0) red |= x0 << 8;
818*61046927SAndroid Build Coastguard Worker    if ((ohm & 0x05) != 0) red |= x0 << 9;
819*61046927SAndroid Build Coastguard Worker    if ((ohm & 0x02) != 0) red |= x6 << 9;
820*61046927SAndroid Build Coastguard Worker    if ((ohm & 0x01) != 0) red |= x3 << 10;
821*61046927SAndroid Build Coastguard Worker    if ((ohm & 0x02) != 0) red |= x5 << 10;
822*61046927SAndroid Build Coastguard Worker
823*61046927SAndroid Build Coastguard Worker    int shamt = max(mode, 1);
824*61046927SAndroid Build Coastguard Worker    red <<= shamt;
825*61046927SAndroid Build Coastguard Worker    green <<= shamt;
826*61046927SAndroid Build Coastguard Worker    blue <<= shamt;
827*61046927SAndroid Build Coastguard Worker    scale <<= shamt;
828*61046927SAndroid Build Coastguard Worker
829*61046927SAndroid Build Coastguard Worker    if (mode != 5)
830*61046927SAndroid Build Coastguard Worker    {
831*61046927SAndroid Build Coastguard Worker        green = red - green;
832*61046927SAndroid Build Coastguard Worker        blue = red - blue;
833*61046927SAndroid Build Coastguard Worker    }
834*61046927SAndroid Build Coastguard Worker
835*61046927SAndroid Build Coastguard Worker    if (major_component == 1)
836*61046927SAndroid Build Coastguard Worker        swap(red, green);
837*61046927SAndroid Build Coastguard Worker    else if (major_component == 2)
838*61046927SAndroid Build Coastguard Worker        swap(red, blue);
839*61046927SAndroid Build Coastguard Worker
840*61046927SAndroid Build Coastguard Worker    ep1 = ivec4(clamp(ivec3(red, green, blue), ivec3(0), ivec3(0xfff)), 0x780);
841*61046927SAndroid Build Coastguard Worker    ep0 = ivec4(clamp(ivec3(red, green, blue) - scale, ivec3(0), ivec3(0xfff)), 0x780);
842*61046927SAndroid Build Coastguard Worker}
843*61046927SAndroid Build Coastguard Worker
844*61046927SAndroid Build Coastguard Workervoid decode_endpoint_hdr_rgb_direct(out ivec4 ep0, out ivec4 ep1,
845*61046927SAndroid Build Coastguard Worker        int v0, int v1, int v2, int v3, int v4, int v5)
846*61046927SAndroid Build Coastguard Worker{
847*61046927SAndroid Build Coastguard Worker    int major_component = ((v4 & 0x80) >> 7) | ((v5 & 0x80) >> 6);
848*61046927SAndroid Build Coastguard Worker
849*61046927SAndroid Build Coastguard Worker    if (major_component == 3)
850*61046927SAndroid Build Coastguard Worker    {
851*61046927SAndroid Build Coastguard Worker        ep0 = ivec4(v0 << 4, v2 << 4, (v4 & 0x7f) << 5, 0x780);
852*61046927SAndroid Build Coastguard Worker        ep1 = ivec4(v1 << 4, v3 << 4, (v5 & 0x7f) << 5, 0x780);
853*61046927SAndroid Build Coastguard Worker        return;
854*61046927SAndroid Build Coastguard Worker    }
855*61046927SAndroid Build Coastguard Worker
856*61046927SAndroid Build Coastguard Worker    int mode = ((v1 & 0x80) >> 7) | ((v2 & 0x80) >> 6) | ((v3 & 0x80) >> 5);
857*61046927SAndroid Build Coastguard Worker    int va = v0 | ((v1 & 0x40) << 2);
858*61046927SAndroid Build Coastguard Worker    int vb0 = v2 & 0x3f;
859*61046927SAndroid Build Coastguard Worker    int vb1 =  v3 & 0x3f;
860*61046927SAndroid Build Coastguard Worker    int vc = v1 & 0x3f;
861*61046927SAndroid Build Coastguard Worker    int vd0 = v4 & 0x7f;
862*61046927SAndroid Build Coastguard Worker    int vd1 = v5 & 0x7f;
863*61046927SAndroid Build Coastguard Worker
864*61046927SAndroid Build Coastguard Worker    int d_bits = 7 - (mode & 1);
865*61046927SAndroid Build Coastguard Worker    if ((mode & 5) == 4)
866*61046927SAndroid Build Coastguard Worker        d_bits -= 2;
867*61046927SAndroid Build Coastguard Worker
868*61046927SAndroid Build Coastguard Worker    vd0 = bitfieldExtract(vd0, 0, d_bits);
869*61046927SAndroid Build Coastguard Worker    vd1 = bitfieldExtract(vd1, 0, d_bits);
870*61046927SAndroid Build Coastguard Worker
871*61046927SAndroid Build Coastguard Worker    int x0 = (v2 >> 6) & 1;
872*61046927SAndroid Build Coastguard Worker    int x1 = (v3 >> 6) & 1;
873*61046927SAndroid Build Coastguard Worker    int x2 = (v4 >> 6) & 1;
874*61046927SAndroid Build Coastguard Worker    int x3 = (v5 >> 6) & 1;
875*61046927SAndroid Build Coastguard Worker    int x4 = (v4 >> 5) & 1;
876*61046927SAndroid Build Coastguard Worker    int x5 = (v5 >> 5) & 1;
877*61046927SAndroid Build Coastguard Worker
878*61046927SAndroid Build Coastguard Worker    int ohm = 1 << mode;
879*61046927SAndroid Build Coastguard Worker    if ((ohm & 0xa4) != 0) va |= x0 << 9;
880*61046927SAndroid Build Coastguard Worker    if ((ohm & 0x08) != 0) va |= x2 << 9;
881*61046927SAndroid Build Coastguard Worker    if ((ohm & 0x50) != 0) va |= x4 << 9;
882*61046927SAndroid Build Coastguard Worker    if ((ohm & 0x50) != 0) va |= x5 << 10;
883*61046927SAndroid Build Coastguard Worker    if ((ohm & 0xa0) != 0) va |= x1 << 10;
884*61046927SAndroid Build Coastguard Worker    if ((ohm & 0xc0) != 0) va |= x2 << 11;
885*61046927SAndroid Build Coastguard Worker
886*61046927SAndroid Build Coastguard Worker    if ((ohm & 0x04) != 0) vc |= x1 << 6;
887*61046927SAndroid Build Coastguard Worker    if ((ohm & 0xe8) != 0) vc |= x3 << 6;
888*61046927SAndroid Build Coastguard Worker    if ((ohm & 0x20) != 0) vc |= x2 << 7;
889*61046927SAndroid Build Coastguard Worker
890*61046927SAndroid Build Coastguard Worker    if ((ohm & 0x5b) != 0) vb0 |= x0 << 6;
891*61046927SAndroid Build Coastguard Worker    if ((ohm & 0x5b) != 0) vb1 |= x1 << 6;
892*61046927SAndroid Build Coastguard Worker    if ((ohm & 0x12) != 0) vb0 |= x2 << 7;
893*61046927SAndroid Build Coastguard Worker    if ((ohm & 0x12) != 0) vb1 |= x3 << 7;
894*61046927SAndroid Build Coastguard Worker
895*61046927SAndroid Build Coastguard Worker    int shamt = (mode >> 1) ^ 3;
896*61046927SAndroid Build Coastguard Worker    va <<= shamt;
897*61046927SAndroid Build Coastguard Worker    vb0 <<= shamt;
898*61046927SAndroid Build Coastguard Worker    vb1 <<= shamt;
899*61046927SAndroid Build Coastguard Worker    vc <<= shamt;
900*61046927SAndroid Build Coastguard Worker    vd0 <<= shamt;
901*61046927SAndroid Build Coastguard Worker    vd1 <<= shamt;
902*61046927SAndroid Build Coastguard Worker
903*61046927SAndroid Build Coastguard Worker    ep1 = ivec4(clamp(ivec3(va, va - vb0, va - vb1), ivec3(0), ivec3(0xfff)), 0x780);
904*61046927SAndroid Build Coastguard Worker    ep0 = ivec4(clamp(ivec3(va - vc, va - vb0 - vc - vd0, va - vb1 - vc - vd1), ivec3(0), ivec3(0xfff)), 0x780);
905*61046927SAndroid Build Coastguard Worker
906*61046927SAndroid Build Coastguard Worker    if (major_component == 1)
907*61046927SAndroid Build Coastguard Worker    {
908*61046927SAndroid Build Coastguard Worker        swap(ep0.r, ep0.g);
909*61046927SAndroid Build Coastguard Worker        swap(ep1.r, ep1.g);
910*61046927SAndroid Build Coastguard Worker    }
911*61046927SAndroid Build Coastguard Worker    else if (major_component == 2)
912*61046927SAndroid Build Coastguard Worker    {
913*61046927SAndroid Build Coastguard Worker        swap(ep0.r, ep0.b);
914*61046927SAndroid Build Coastguard Worker        swap(ep1.r, ep1.b);
915*61046927SAndroid Build Coastguard Worker    }
916*61046927SAndroid Build Coastguard Worker}
917*61046927SAndroid Build Coastguard Worker
918*61046927SAndroid Build Coastguard Workervoid decode_endpoint_ldr_rgb_base_offset(out ivec4 ep0, out ivec4 ep1,
919*61046927SAndroid Build Coastguard Worker        int v0, int v1, int v2, int v3, int v4, int v5)
920*61046927SAndroid Build Coastguard Worker{
921*61046927SAndroid Build Coastguard Worker    bit_transfer_signed(v1, v0);
922*61046927SAndroid Build Coastguard Worker    bit_transfer_signed(v3, v2);
923*61046927SAndroid Build Coastguard Worker    bit_transfer_signed(v5, v4);
924*61046927SAndroid Build Coastguard Worker    if (v1 + v3 + v5 >= 0)
925*61046927SAndroid Build Coastguard Worker    {
926*61046927SAndroid Build Coastguard Worker        ep0 = ivec4(v0, v2, v4, 0xff);
927*61046927SAndroid Build Coastguard Worker        ep1 = ivec4(v0 + v1, v2 + v3, v4 + v5, 0xff);
928*61046927SAndroid Build Coastguard Worker    }
929*61046927SAndroid Build Coastguard Worker    else
930*61046927SAndroid Build Coastguard Worker    {
931*61046927SAndroid Build Coastguard Worker        ep0 = blue_contract(v0 + v1, v2 + v3, v4 + v5, 0xff);
932*61046927SAndroid Build Coastguard Worker        ep1 = blue_contract(v0, v2, v4, 0xff);
933*61046927SAndroid Build Coastguard Worker    }
934*61046927SAndroid Build Coastguard Worker
935*61046927SAndroid Build Coastguard Worker    ep0.rgb = clamp(ep0.rgb, ivec3(0), ivec3(0xff));
936*61046927SAndroid Build Coastguard Worker    ep1.rgb = clamp(ep1.rgb, ivec3(0), ivec3(0xff));
937*61046927SAndroid Build Coastguard Worker}
938*61046927SAndroid Build Coastguard Worker
939*61046927SAndroid Build Coastguard Workervoid decode_endpoint_ldr_rgba_direct(out ivec4 ep0, out ivec4 ep1,
940*61046927SAndroid Build Coastguard Worker        int v0, int v1, int v2, int v3,
941*61046927SAndroid Build Coastguard Worker        int v4, int v5, int v6, int v7)
942*61046927SAndroid Build Coastguard Worker{
943*61046927SAndroid Build Coastguard Worker    int s0 = v0 + v2 + v4;
944*61046927SAndroid Build Coastguard Worker    int s1 = v1 + v3 + v5;
945*61046927SAndroid Build Coastguard Worker    if (s1 >= s0)
946*61046927SAndroid Build Coastguard Worker    {
947*61046927SAndroid Build Coastguard Worker        ep0 = ivec4(v0, v2, v4, v6);
948*61046927SAndroid Build Coastguard Worker        ep1 = ivec4(v1, v3, v5, v7);
949*61046927SAndroid Build Coastguard Worker    }
950*61046927SAndroid Build Coastguard Worker    else
951*61046927SAndroid Build Coastguard Worker    {
952*61046927SAndroid Build Coastguard Worker        ep0 = blue_contract(v1, v3, v5, v7);
953*61046927SAndroid Build Coastguard Worker        ep1 = blue_contract(v0, v2, v4, v6);
954*61046927SAndroid Build Coastguard Worker    }
955*61046927SAndroid Build Coastguard Worker}
956*61046927SAndroid Build Coastguard Worker
957*61046927SAndroid Build Coastguard Workervoid decode_endpoint_ldr_rgba_base_offset(out ivec4 ep0, out ivec4 ep1,
958*61046927SAndroid Build Coastguard Worker        int v0, int v1, int v2, int v3, int v4, int v5, int v6, int v7)
959*61046927SAndroid Build Coastguard Worker{
960*61046927SAndroid Build Coastguard Worker    bit_transfer_signed(v1, v0);
961*61046927SAndroid Build Coastguard Worker    bit_transfer_signed(v3, v2);
962*61046927SAndroid Build Coastguard Worker    bit_transfer_signed(v5, v4);
963*61046927SAndroid Build Coastguard Worker    bit_transfer_signed(v7, v6);
964*61046927SAndroid Build Coastguard Worker
965*61046927SAndroid Build Coastguard Worker    if (v1 + v3 + v5 >= 0)
966*61046927SAndroid Build Coastguard Worker    {
967*61046927SAndroid Build Coastguard Worker        ep0 = ivec4(v0, v2, v4, v6);
968*61046927SAndroid Build Coastguard Worker        ep1 = ivec4(v0 + v1, v2 + v3, v4 + v5, v6 + v7);
969*61046927SAndroid Build Coastguard Worker    }
970*61046927SAndroid Build Coastguard Worker    else
971*61046927SAndroid Build Coastguard Worker    {
972*61046927SAndroid Build Coastguard Worker        ep0 = blue_contract(v0 + v1, v2 + v3, v4 + v5, v6 + v7);
973*61046927SAndroid Build Coastguard Worker        ep1 = blue_contract(v0, v2, v4, v6);
974*61046927SAndroid Build Coastguard Worker    }
975*61046927SAndroid Build Coastguard Worker
976*61046927SAndroid Build Coastguard Worker    ep0 = clamp(ep0, ivec4(0), ivec4(0xff));
977*61046927SAndroid Build Coastguard Worker    ep1 = clamp(ep1, ivec4(0), ivec4(0xff));
978*61046927SAndroid Build Coastguard Worker}
979*61046927SAndroid Build Coastguard Worker
980*61046927SAndroid Build Coastguard Workervoid decode_endpoint_hdr_alpha(out int ep0, out int ep1, int v6, int v7)
981*61046927SAndroid Build Coastguard Worker{
982*61046927SAndroid Build Coastguard Worker    int mode = ((v6 >> 7) & 1) | ((v7 >> 6) & 2);
983*61046927SAndroid Build Coastguard Worker    v6 &= 0x7f;
984*61046927SAndroid Build Coastguard Worker    v7 &= 0x7f;
985*61046927SAndroid Build Coastguard Worker
986*61046927SAndroid Build Coastguard Worker    if (mode == 3)
987*61046927SAndroid Build Coastguard Worker    {
988*61046927SAndroid Build Coastguard Worker        ep0 = v6 << 5;
989*61046927SAndroid Build Coastguard Worker        ep1 = v7 << 5;
990*61046927SAndroid Build Coastguard Worker    }
991*61046927SAndroid Build Coastguard Worker    else
992*61046927SAndroid Build Coastguard Worker    {
993*61046927SAndroid Build Coastguard Worker        v6 |= (v7 << (mode + 1)) & 0x780;
994*61046927SAndroid Build Coastguard Worker        v7 &= 0x3f >> mode;
995*61046927SAndroid Build Coastguard Worker        v7 ^= 0x20 >> mode;
996*61046927SAndroid Build Coastguard Worker        v7 -= 0x20 >> mode;
997*61046927SAndroid Build Coastguard Worker        v6 <<= 4 - mode;
998*61046927SAndroid Build Coastguard Worker        v7 <<= 4 - mode;
999*61046927SAndroid Build Coastguard Worker        v7 += v6;
1000*61046927SAndroid Build Coastguard Worker        v7 = clamp(v7, 0, 0xfff);
1001*61046927SAndroid Build Coastguard Worker        ep0 = v6;
1002*61046927SAndroid Build Coastguard Worker        ep1 = v7;
1003*61046927SAndroid Build Coastguard Worker    }
1004*61046927SAndroid Build Coastguard Worker}
1005*61046927SAndroid Build Coastguard Worker
1006*61046927SAndroid Build Coastguard Workervoid decode_endpoint(out ivec4 ep0, out ivec4 ep1, out int decode_mode,
1007*61046927SAndroid Build Coastguard Worker                     uvec4 payload, int bit_offset, ivec4 quant, int ep_mode,
1008*61046927SAndroid Build Coastguard Worker                     int base_endpoint_index, int num_endpoint_bits)
1009*61046927SAndroid Build Coastguard Worker{
1010*61046927SAndroid Build Coastguard Worker    num_endpoint_bits += bit_offset;
1011*61046927SAndroid Build Coastguard Worker    payload &= build_bitmask(num_endpoint_bits);
1012*61046927SAndroid Build Coastguard Worker
1013*61046927SAndroid Build Coastguard Worker    // Could of course use an array, but that doesn't lower nicely to indexed registers on all GPUs.
1014*61046927SAndroid Build Coastguard Worker    int v0, v1, v2, v3, v4, v5, v6, v7;
1015*61046927SAndroid Build Coastguard Worker    int num_values = 2 * ((ep_mode >> 2) + 1);
1016*61046927SAndroid Build Coastguard Worker
1017*61046927SAndroid Build Coastguard Worker#define DECODE_EP(i) \
1018*61046927SAndroid Build Coastguard Worker    int(texelFetch(LUTEndpointUnquantize, quant.w + decode_integer_sequence(payload, bit_offset, i + base_endpoint_index, quant.xyz)).x)
1019*61046927SAndroid Build Coastguard Worker
1020*61046927SAndroid Build Coastguard Worker    int hi_bits = ep_mode >> 2;
1021*61046927SAndroid Build Coastguard Worker    v0 = DECODE_EP(0);
1022*61046927SAndroid Build Coastguard Worker    v1 = DECODE_EP(1);
1023*61046927SAndroid Build Coastguard Worker
1024*61046927SAndroid Build Coastguard Worker    if (hi_bits >= 1)
1025*61046927SAndroid Build Coastguard Worker    {
1026*61046927SAndroid Build Coastguard Worker        v2 = DECODE_EP(2);
1027*61046927SAndroid Build Coastguard Worker        v3 = DECODE_EP(3);
1028*61046927SAndroid Build Coastguard Worker    }
1029*61046927SAndroid Build Coastguard Worker
1030*61046927SAndroid Build Coastguard Worker    if (hi_bits >= 2)
1031*61046927SAndroid Build Coastguard Worker    {
1032*61046927SAndroid Build Coastguard Worker        v4 = DECODE_EP(4);
1033*61046927SAndroid Build Coastguard Worker        v5 = DECODE_EP(5);
1034*61046927SAndroid Build Coastguard Worker    }
1035*61046927SAndroid Build Coastguard Worker
1036*61046927SAndroid Build Coastguard Worker    if (hi_bits >= 3)
1037*61046927SAndroid Build Coastguard Worker    {
1038*61046927SAndroid Build Coastguard Worker        v6 = DECODE_EP(6);
1039*61046927SAndroid Build Coastguard Worker        v7 = DECODE_EP(7);
1040*61046927SAndroid Build Coastguard Worker    }
1041*61046927SAndroid Build Coastguard Worker
1042*61046927SAndroid Build Coastguard Worker    switch (ep_mode)
1043*61046927SAndroid Build Coastguard Worker    {
1044*61046927SAndroid Build Coastguard Worker    case 0:
1045*61046927SAndroid Build Coastguard Worker        decode_endpoint_ldr_luma_direct(ep0, ep1,
1046*61046927SAndroid Build Coastguard Worker            v0, v1);
1047*61046927SAndroid Build Coastguard Worker        decode_mode = MODE_LDR;
1048*61046927SAndroid Build Coastguard Worker        break;
1049*61046927SAndroid Build Coastguard Worker
1050*61046927SAndroid Build Coastguard Worker    case 1:
1051*61046927SAndroid Build Coastguard Worker        decode_endpoint_ldr_luma_base_offset(ep0, ep1,
1052*61046927SAndroid Build Coastguard Worker            v0, v1);
1053*61046927SAndroid Build Coastguard Worker        decode_mode = MODE_LDR;
1054*61046927SAndroid Build Coastguard Worker        break;
1055*61046927SAndroid Build Coastguard Worker
1056*61046927SAndroid Build Coastguard Worker    case 2:
1057*61046927SAndroid Build Coastguard Worker        decode_endpoint_hdr_luma_direct(ep0, ep1,
1058*61046927SAndroid Build Coastguard Worker            v0, v1);
1059*61046927SAndroid Build Coastguard Worker        decode_mode = MODE_HDR;
1060*61046927SAndroid Build Coastguard Worker        break;
1061*61046927SAndroid Build Coastguard Worker
1062*61046927SAndroid Build Coastguard Worker    case 3:
1063*61046927SAndroid Build Coastguard Worker        decode_endpoint_hdr_luma_direct_small_range(ep0, ep1,
1064*61046927SAndroid Build Coastguard Worker            v0, v1);
1065*61046927SAndroid Build Coastguard Worker        decode_mode = MODE_HDR;
1066*61046927SAndroid Build Coastguard Worker        break;
1067*61046927SAndroid Build Coastguard Worker
1068*61046927SAndroid Build Coastguard Worker    case 4:
1069*61046927SAndroid Build Coastguard Worker        decode_endpoint_ldr_luma_alpha_direct(ep0, ep1,
1070*61046927SAndroid Build Coastguard Worker            v0, v1, v2, v3);
1071*61046927SAndroid Build Coastguard Worker        decode_mode = MODE_LDR;
1072*61046927SAndroid Build Coastguard Worker        break;
1073*61046927SAndroid Build Coastguard Worker
1074*61046927SAndroid Build Coastguard Worker    case 5:
1075*61046927SAndroid Build Coastguard Worker        decode_endpoint_ldr_luma_alpha_base_offset(ep0, ep1,
1076*61046927SAndroid Build Coastguard Worker            v0, v1, v2, v3);
1077*61046927SAndroid Build Coastguard Worker        decode_mode = MODE_LDR;
1078*61046927SAndroid Build Coastguard Worker        break;
1079*61046927SAndroid Build Coastguard Worker
1080*61046927SAndroid Build Coastguard Worker    case 6:
1081*61046927SAndroid Build Coastguard Worker        decode_endpoint_ldr_rgb_base_scale(ep0, ep1,
1082*61046927SAndroid Build Coastguard Worker            v0, v1, v2, v3);
1083*61046927SAndroid Build Coastguard Worker        decode_mode = MODE_LDR;
1084*61046927SAndroid Build Coastguard Worker        break;
1085*61046927SAndroid Build Coastguard Worker
1086*61046927SAndroid Build Coastguard Worker    case 7:
1087*61046927SAndroid Build Coastguard Worker        decode_endpoint_hdr_rgb_scale(ep0, ep1,
1088*61046927SAndroid Build Coastguard Worker            v0, v1, v2, v3);
1089*61046927SAndroid Build Coastguard Worker        decode_mode = MODE_HDR;
1090*61046927SAndroid Build Coastguard Worker        break;
1091*61046927SAndroid Build Coastguard Worker
1092*61046927SAndroid Build Coastguard Worker    case 8:
1093*61046927SAndroid Build Coastguard Worker        decode_endpoint_ldr_rgb_direct(ep0, ep1,
1094*61046927SAndroid Build Coastguard Worker            v0, v1, v2, v3, v4, v5);
1095*61046927SAndroid Build Coastguard Worker        decode_mode = MODE_LDR;
1096*61046927SAndroid Build Coastguard Worker        break;
1097*61046927SAndroid Build Coastguard Worker
1098*61046927SAndroid Build Coastguard Worker    case 9:
1099*61046927SAndroid Build Coastguard Worker        decode_endpoint_ldr_rgb_base_offset(ep0, ep1,
1100*61046927SAndroid Build Coastguard Worker            v0, v1, v2, v3, v4, v5);
1101*61046927SAndroid Build Coastguard Worker        decode_mode = MODE_LDR;
1102*61046927SAndroid Build Coastguard Worker        break;
1103*61046927SAndroid Build Coastguard Worker
1104*61046927SAndroid Build Coastguard Worker    case 10:
1105*61046927SAndroid Build Coastguard Worker        decode_endpoint_ldr_rgb_base_scale_two_a(ep0, ep1,
1106*61046927SAndroid Build Coastguard Worker            v0, v1, v2, v3, v4, v5);
1107*61046927SAndroid Build Coastguard Worker        decode_mode = MODE_LDR;
1108*61046927SAndroid Build Coastguard Worker        break;
1109*61046927SAndroid Build Coastguard Worker
1110*61046927SAndroid Build Coastguard Worker    case 11:
1111*61046927SAndroid Build Coastguard Worker    case 14:
1112*61046927SAndroid Build Coastguard Worker    case 15:
1113*61046927SAndroid Build Coastguard Worker        decode_endpoint_hdr_rgb_direct(ep0, ep1,
1114*61046927SAndroid Build Coastguard Worker            v0, v1, v2, v3, v4, v5);
1115*61046927SAndroid Build Coastguard Worker        if (ep_mode == 14)
1116*61046927SAndroid Build Coastguard Worker        {
1117*61046927SAndroid Build Coastguard Worker            ep0.a = v6;
1118*61046927SAndroid Build Coastguard Worker            ep1.a = v7;
1119*61046927SAndroid Build Coastguard Worker            decode_mode = MODE_HDR_LDR_ALPHA;
1120*61046927SAndroid Build Coastguard Worker        }
1121*61046927SAndroid Build Coastguard Worker        else if (ep_mode == 15)
1122*61046927SAndroid Build Coastguard Worker        {
1123*61046927SAndroid Build Coastguard Worker            decode_endpoint_hdr_alpha(ep0.a, ep1.a, v6, v7);
1124*61046927SAndroid Build Coastguard Worker            decode_mode = MODE_HDR;
1125*61046927SAndroid Build Coastguard Worker        }
1126*61046927SAndroid Build Coastguard Worker        else
1127*61046927SAndroid Build Coastguard Worker            decode_mode = MODE_HDR;
1128*61046927SAndroid Build Coastguard Worker        break;
1129*61046927SAndroid Build Coastguard Worker
1130*61046927SAndroid Build Coastguard Worker    case 12:
1131*61046927SAndroid Build Coastguard Worker        decode_endpoint_ldr_rgba_direct(ep0, ep1,
1132*61046927SAndroid Build Coastguard Worker            v0, v1, v2, v3, v4, v5, v6, v7);
1133*61046927SAndroid Build Coastguard Worker        decode_mode = MODE_LDR;
1134*61046927SAndroid Build Coastguard Worker        break;
1135*61046927SAndroid Build Coastguard Worker
1136*61046927SAndroid Build Coastguard Worker    case 13:
1137*61046927SAndroid Build Coastguard Worker        decode_endpoint_ldr_rgba_base_offset(ep0, ep1,
1138*61046927SAndroid Build Coastguard Worker            v0, v1, v2, v3, v4, v5, v6, v7);
1139*61046927SAndroid Build Coastguard Worker        decode_mode = MODE_LDR;
1140*61046927SAndroid Build Coastguard Worker        break;
1141*61046927SAndroid Build Coastguard Worker    }
1142*61046927SAndroid Build Coastguard Worker
1143*61046927SAndroid Build Coastguard Worker    if (DECODE_8BIT && decode_mode != MODE_LDR)
1144*61046927SAndroid Build Coastguard Worker        decode_error = true;
1145*61046927SAndroid Build Coastguard Worker}
1146*61046927SAndroid Build Coastguard Worker
1147*61046927SAndroid Build Coastguard Worker#define CHECK_DECODE_ERROR() do { \
1148*61046927SAndroid Build Coastguard Worker    if (decode_error) \
1149*61046927SAndroid Build Coastguard Worker    { \
1150*61046927SAndroid Build Coastguard Worker        emit_decode_error(coord.xy); \
1151*61046927SAndroid Build Coastguard Worker        return; \
1152*61046927SAndroid Build Coastguard Worker    } \
1153*61046927SAndroid Build Coastguard Worker} while(false)
1154*61046927SAndroid Build Coastguard Worker
1155*61046927SAndroid Build Coastguard Workervoid emit_decode_error(ivec2 coord)
1156*61046927SAndroid Build Coastguard Worker{
1157*61046927SAndroid Build Coastguard Worker#ifdef VULKAN
1158*61046927SAndroid Build Coastguard Worker    if (is_3Dimage)
1159*61046927SAndroid Build Coastguard Worker        imageStore(OutputImage3D, ivec3(coord, gl_WorkGroupID.z), error_color);
1160*61046927SAndroid Build Coastguard Worker    else
1161*61046927SAndroid Build Coastguard Worker        imageStore(OutputImage2Darray, ivec3(coord, gl_WorkGroupID.z), error_color);
1162*61046927SAndroid Build Coastguard Worker#else /* VULKAN */
1163*61046927SAndroid Build Coastguard Worker    imageStore(OutputImage, coord, error_color);
1164*61046927SAndroid Build Coastguard Worker#endif /* VULKAN */
1165*61046927SAndroid Build Coastguard Worker}
1166*61046927SAndroid Build Coastguard Worker
1167*61046927SAndroid Build Coastguard Workerint compute_num_endpoint_pairs(int num_partitions, int cem)
1168*61046927SAndroid Build Coastguard Worker{
1169*61046927SAndroid Build Coastguard Worker    int ret;
1170*61046927SAndroid Build Coastguard Worker    if (num_partitions > 1)
1171*61046927SAndroid Build Coastguard Worker    {
1172*61046927SAndroid Build Coastguard Worker        bool single_cem = (cem & 3) == 0;
1173*61046927SAndroid Build Coastguard Worker        if (single_cem)
1174*61046927SAndroid Build Coastguard Worker            ret = ((cem >> 4) + 1) * num_partitions;
1175*61046927SAndroid Build Coastguard Worker        else
1176*61046927SAndroid Build Coastguard Worker            ret = (cem & 3) * num_partitions + bitCount(bitfieldExtract(uint(cem), 2, num_partitions));
1177*61046927SAndroid Build Coastguard Worker    }
1178*61046927SAndroid Build Coastguard Worker    else
1179*61046927SAndroid Build Coastguard Worker    {
1180*61046927SAndroid Build Coastguard Worker        ret = (cem >> 2) + 1;
1181*61046927SAndroid Build Coastguard Worker    }
1182*61046927SAndroid Build Coastguard Worker    return ret;
1183*61046927SAndroid Build Coastguard Worker}
1184*61046927SAndroid Build Coastguard Worker
1185*61046927SAndroid Build Coastguard Workervoid decode_cem_base_endpoint(uvec4 payload, int weight_cost_bits, inout int cem, out int base_endpoint_index,
1186*61046927SAndroid Build Coastguard Worker    int num_partitions, int partition_index)
1187*61046927SAndroid Build Coastguard Worker{
1188*61046927SAndroid Build Coastguard Worker    if (num_partitions > 1)
1189*61046927SAndroid Build Coastguard Worker    {
1190*61046927SAndroid Build Coastguard Worker        bool single_cem = (cem & 3) == 0;
1191*61046927SAndroid Build Coastguard Worker        if (single_cem)
1192*61046927SAndroid Build Coastguard Worker        {
1193*61046927SAndroid Build Coastguard Worker            cem >>= 2;
1194*61046927SAndroid Build Coastguard Worker            base_endpoint_index = ((cem >> 2) + 1) * partition_index;
1195*61046927SAndroid Build Coastguard Worker        }
1196*61046927SAndroid Build Coastguard Worker        else
1197*61046927SAndroid Build Coastguard Worker        {
1198*61046927SAndroid Build Coastguard Worker            if (partition_index != 0)
1199*61046927SAndroid Build Coastguard Worker                base_endpoint_index = (cem & 3) * partition_index + bitCount(bitfieldExtract(uint(cem), 2, partition_index));
1200*61046927SAndroid Build Coastguard Worker            else
1201*61046927SAndroid Build Coastguard Worker                base_endpoint_index = 0;
1202*61046927SAndroid Build Coastguard Worker
1203*61046927SAndroid Build Coastguard Worker            int base_class = (cem & 3) - 1;
1204*61046927SAndroid Build Coastguard Worker            int extra_cem_bits = num_partitions * 3 - 4;
1205*61046927SAndroid Build Coastguard Worker            int extra_bits = extract_bits(payload, 128 - weight_cost_bits - extra_cem_bits, extra_cem_bits);
1206*61046927SAndroid Build Coastguard Worker            cem = (extra_bits << 4) | (cem >> 2);
1207*61046927SAndroid Build Coastguard Worker
1208*61046927SAndroid Build Coastguard Worker            int class_offset_bit = (cem >> partition_index) & 1;
1209*61046927SAndroid Build Coastguard Worker            int ep_bits = (cem >> (num_partitions + 2 * partition_index)) & 3;
1210*61046927SAndroid Build Coastguard Worker
1211*61046927SAndroid Build Coastguard Worker            cem = 4 * (base_class + class_offset_bit) + ep_bits;
1212*61046927SAndroid Build Coastguard Worker        }
1213*61046927SAndroid Build Coastguard Worker        base_endpoint_index *= 2;
1214*61046927SAndroid Build Coastguard Worker    }
1215*61046927SAndroid Build Coastguard Worker    else
1216*61046927SAndroid Build Coastguard Worker    {
1217*61046927SAndroid Build Coastguard Worker        base_endpoint_index = 0;
1218*61046927SAndroid Build Coastguard Worker    }
1219*61046927SAndroid Build Coastguard Worker}
1220*61046927SAndroid Build Coastguard Worker
1221*61046927SAndroid Build Coastguard Workerivec4 void_extent_color(uvec4 payload, out int decode_mode)
1222*61046927SAndroid Build Coastguard Worker{
1223*61046927SAndroid Build Coastguard Worker    int min_s = extract_bits(payload, 12, 13);
1224*61046927SAndroid Build Coastguard Worker    int max_s = extract_bits(payload, 12 + 13, 13);
1225*61046927SAndroid Build Coastguard Worker    int min_t = extract_bits(payload, 12 + 2 * 13, 13);
1226*61046927SAndroid Build Coastguard Worker    int max_t = extract_bits(payload, 12 + 3 * 13, 13);
1227*61046927SAndroid Build Coastguard Worker
1228*61046927SAndroid Build Coastguard Worker    int reserved = extract_bits(payload, 10, 2);
1229*61046927SAndroid Build Coastguard Worker    if (reserved != 3)
1230*61046927SAndroid Build Coastguard Worker    {
1231*61046927SAndroid Build Coastguard Worker        decode_error = true;
1232*61046927SAndroid Build Coastguard Worker        return ivec4(0);
1233*61046927SAndroid Build Coastguard Worker    }
1234*61046927SAndroid Build Coastguard Worker
1235*61046927SAndroid Build Coastguard Worker    if (!all(equal(ivec4(min_s, max_s, min_t, max_t), ivec4((1 << 13) - 1))))
1236*61046927SAndroid Build Coastguard Worker    {
1237*61046927SAndroid Build Coastguard Worker        if (any(greaterThanEqual(ivec2(min_s, min_t), ivec2(max_s, max_t))))
1238*61046927SAndroid Build Coastguard Worker        {
1239*61046927SAndroid Build Coastguard Worker            decode_error = true;
1240*61046927SAndroid Build Coastguard Worker            return ivec4(0);
1241*61046927SAndroid Build Coastguard Worker        }
1242*61046927SAndroid Build Coastguard Worker    }
1243*61046927SAndroid Build Coastguard Worker
1244*61046927SAndroid Build Coastguard Worker    decode_mode = (payload.x & (1u << 9)) != 0u ? MODE_HDR : MODE_LDR;
1245*61046927SAndroid Build Coastguard Worker
1246*61046927SAndroid Build Coastguard Worker    int r = extract_bits(payload, 64, 16);
1247*61046927SAndroid Build Coastguard Worker    int g = extract_bits(payload, 64 + 16, 16);
1248*61046927SAndroid Build Coastguard Worker    int b = extract_bits(payload, 64 + 32, 16);
1249*61046927SAndroid Build Coastguard Worker    int a = extract_bits(payload, 64 + 48, 16);
1250*61046927SAndroid Build Coastguard Worker
1251*61046927SAndroid Build Coastguard Worker    return ivec4(r, g, b, a);
1252*61046927SAndroid Build Coastguard Worker}
1253*61046927SAndroid Build Coastguard Worker
1254*61046927SAndroid Build Coastguard Workervoid main()
1255*61046927SAndroid Build Coastguard Worker{
1256*61046927SAndroid Build Coastguard Worker    ivec4 coord = build_coord();
1257*61046927SAndroid Build Coastguard Worker#ifdef VULKAN
1258*61046927SAndroid Build Coastguard Worker    if (any(greaterThanEqual(coord.xy, texel_end.xy)))
1259*61046927SAndroid Build Coastguard Worker        return;
1260*61046927SAndroid Build Coastguard Worker#else /* VULKAN */
1261*61046927SAndroid Build Coastguard Worker    if (any(greaterThanEqual(coord.xy, imageSize(OutputImage))))
1262*61046927SAndroid Build Coastguard Worker        return;
1263*61046927SAndroid Build Coastguard Worker#endif /* VULKAN */
1264*61046927SAndroid Build Coastguard Worker
1265*61046927SAndroid Build Coastguard Worker    ivec2 pixel_coord = ivec2(gl_LocalInvocationID.xy);
1266*61046927SAndroid Build Coastguard Worker    int linear_pixel = int(gl_WorkGroupSize.x) * pixel_coord.y + pixel_coord.x;
1267*61046927SAndroid Build Coastguard Worker    uvec4 payload;
1268*61046927SAndroid Build Coastguard Worker#ifdef VULKAN
1269*61046927SAndroid Build Coastguard Worker    if (is_3Dimage)
1270*61046927SAndroid Build Coastguard Worker        payload = texelFetch(PayloadInput3D, ivec3(coord.zw, gl_WorkGroupID.z), 0);
1271*61046927SAndroid Build Coastguard Worker    else
1272*61046927SAndroid Build Coastguard Worker        payload = texelFetch(PayloadInput2Darray,ivec3(coord.zw, gl_WorkGroupID.z), 0);
1273*61046927SAndroid Build Coastguard Worker#else /* VULKAN */
1274*61046927SAndroid Build Coastguard Worker    payload = texelFetch(PayloadInput, coord.zw, 0);
1275*61046927SAndroid Build Coastguard Worker#endif /* VULKAN */
1276*61046927SAndroid Build Coastguard Worker
1277*61046927SAndroid Build Coastguard Worker    BlockMode block_mode = decode_block_mode(payload);
1278*61046927SAndroid Build Coastguard Worker    CHECK_DECODE_ERROR();
1279*61046927SAndroid Build Coastguard Worker
1280*61046927SAndroid Build Coastguard Worker    ivec4 final_color;
1281*61046927SAndroid Build Coastguard Worker    int decode_mode;
1282*61046927SAndroid Build Coastguard Worker    if (block_mode.void_extent)
1283*61046927SAndroid Build Coastguard Worker    {
1284*61046927SAndroid Build Coastguard Worker        final_color = void_extent_color(payload, decode_mode);
1285*61046927SAndroid Build Coastguard Worker        CHECK_DECODE_ERROR();
1286*61046927SAndroid Build Coastguard Worker    }
1287*61046927SAndroid Build Coastguard Worker    else
1288*61046927SAndroid Build Coastguard Worker    {
1289*61046927SAndroid Build Coastguard Worker        int weight_cost_bits;
1290*61046927SAndroid Build Coastguard Worker        ivec4 weights = decode_weights(payload, block_mode, normalize_coord(pixel_coord), weight_cost_bits);
1291*61046927SAndroid Build Coastguard Worker
1292*61046927SAndroid Build Coastguard Worker        int partition_index = 0;
1293*61046927SAndroid Build Coastguard Worker        if (block_mode.num_partitions > 1)
1294*61046927SAndroid Build Coastguard Worker        {
1295*61046927SAndroid Build Coastguard Worker            int lut_x = pixel_coord.x + int(gl_WorkGroupSize.x) * (block_mode.seed & 31);
1296*61046927SAndroid Build Coastguard Worker            int lut_y = pixel_coord.y + int(gl_WorkGroupSize.y) * (block_mode.seed >> 5);
1297*61046927SAndroid Build Coastguard Worker#ifdef VULKAN
1298*61046927SAndroid Build Coastguard Worker            int lut_width = int(gl_WorkGroupSize.x) * 32;
1299*61046927SAndroid Build Coastguard Worker            partition_index = int(texelFetch(LUTPartitionTable, lut_y * lut_width + lut_x).x);
1300*61046927SAndroid Build Coastguard Worker#else /* VULKAN */
1301*61046927SAndroid Build Coastguard Worker            partition_index = int(texelFetch(LUTPartitionTable, ivec2(lut_x, lut_y), 0).x);
1302*61046927SAndroid Build Coastguard Worker#endif /* VULKAN */
1303*61046927SAndroid Build Coastguard Worker            partition_index = (partition_index >> (2 * block_mode.num_partitions - 4)) & 3;
1304*61046927SAndroid Build Coastguard Worker        }
1305*61046927SAndroid Build Coastguard Worker
1306*61046927SAndroid Build Coastguard Worker        int available_endpoint_bits = max(128 - block_mode.config_bits - weight_cost_bits, 0);
1307*61046927SAndroid Build Coastguard Worker
1308*61046927SAndroid Build Coastguard Worker        // In multi-partition mode, the 6-bit CEM field is encoded as
1309*61046927SAndroid Build Coastguard Worker        // First two bits tell if all CEM field are the same, if not we specify a class offset, and N bits
1310*61046927SAndroid Build Coastguard Worker        // after that will offset the class by 1.
1311*61046927SAndroid Build Coastguard Worker        int num_endpoint_pairs = compute_num_endpoint_pairs(block_mode.num_partitions, block_mode.cem);
1312*61046927SAndroid Build Coastguard Worker
1313*61046927SAndroid Build Coastguard Worker        // Error color must be emitted if we need more than 18 integer sequence encoded values of color.
1314*61046927SAndroid Build Coastguard Worker        if (num_endpoint_pairs > 9)
1315*61046927SAndroid Build Coastguard Worker        {
1316*61046927SAndroid Build Coastguard Worker            decode_error = true;
1317*61046927SAndroid Build Coastguard Worker            emit_decode_error(coord.xy);
1318*61046927SAndroid Build Coastguard Worker            return;
1319*61046927SAndroid Build Coastguard Worker        }
1320*61046927SAndroid Build Coastguard Worker
1321*61046927SAndroid Build Coastguard Worker        ivec4 endpoint_quant = ivec4(texelFetch(LUTRemainingBitsToEndpointQuantizer,
1322*61046927SAndroid Build Coastguard Worker                128 * (num_endpoint_pairs - 1) + available_endpoint_bits));
1323*61046927SAndroid Build Coastguard Worker
1324*61046927SAndroid Build Coastguard Worker        // Only read the bits we need for endpoints.
1325*61046927SAndroid Build Coastguard Worker        int num_endpoint_values = num_endpoint_pairs * 2;
1326*61046927SAndroid Build Coastguard Worker        available_endpoint_bits =
1327*61046927SAndroid Build Coastguard Worker            endpoint_quant.x * num_endpoint_values +
1328*61046927SAndroid Build Coastguard Worker            idiv5_ceil(endpoint_quant.y * 8 * num_endpoint_values) +
1329*61046927SAndroid Build Coastguard Worker            idiv3_ceil(endpoint_quant.z * 7 * num_endpoint_values);
1330*61046927SAndroid Build Coastguard Worker
1331*61046927SAndroid Build Coastguard Worker        // No space left for color endpoints.
1332*61046927SAndroid Build Coastguard Worker        if (all(equal(endpoint_quant.xyz, ivec3(0))))
1333*61046927SAndroid Build Coastguard Worker        {
1334*61046927SAndroid Build Coastguard Worker            decode_error = true;
1335*61046927SAndroid Build Coastguard Worker            emit_decode_error(coord.xy);
1336*61046927SAndroid Build Coastguard Worker            return;
1337*61046927SAndroid Build Coastguard Worker        }
1338*61046927SAndroid Build Coastguard Worker
1339*61046927SAndroid Build Coastguard Worker        int endpoint_bit_offset = block_mode.primary_config_bits;
1340*61046927SAndroid Build Coastguard Worker        ivec4 ep0, ep1;
1341*61046927SAndroid Build Coastguard Worker
1342*61046927SAndroid Build Coastguard Worker        // Decode CEM for multi-partition schemes.
1343*61046927SAndroid Build Coastguard Worker        int cem = block_mode.cem;
1344*61046927SAndroid Build Coastguard Worker        int base_endpoint_index;
1345*61046927SAndroid Build Coastguard Worker        decode_cem_base_endpoint(payload, weight_cost_bits, cem, base_endpoint_index,
1346*61046927SAndroid Build Coastguard Worker                                 block_mode.num_partitions, partition_index);
1347*61046927SAndroid Build Coastguard Worker
1348*61046927SAndroid Build Coastguard Worker        decode_endpoint(ep0, ep1, decode_mode, payload, endpoint_bit_offset, endpoint_quant,
1349*61046927SAndroid Build Coastguard Worker                        cem, base_endpoint_index, available_endpoint_bits);
1350*61046927SAndroid Build Coastguard Worker        CHECK_DECODE_ERROR();
1351*61046927SAndroid Build Coastguard Worker
1352*61046927SAndroid Build Coastguard Worker        final_color = interpolate_endpoint(ep0, ep1, weights, decode_mode);
1353*61046927SAndroid Build Coastguard Worker    }
1354*61046927SAndroid Build Coastguard Worker
1355*61046927SAndroid Build Coastguard Worker    if (DECODE_8BIT)
1356*61046927SAndroid Build Coastguard Worker    {
1357*61046927SAndroid Build Coastguard Worker#ifdef VULKAN
1358*61046927SAndroid Build Coastguard Worker        if (is_3Dimage)
1359*61046927SAndroid Build Coastguard Worker            imageStore(OutputImage3D, ivec3(coord.xy, gl_WorkGroupID.z), uvec4(final_color >> 8));
1360*61046927SAndroid Build Coastguard Worker        else
1361*61046927SAndroid Build Coastguard Worker            imageStore(OutputImage2Darray, ivec3(coord.xy, gl_WorkGroupID.z), uvec4(final_color >> 8));
1362*61046927SAndroid Build Coastguard Worker#else /* VULKAN */
1363*61046927SAndroid Build Coastguard Worker        imageStore(OutputImage, coord.xy, uvec4(final_color >> 8));
1364*61046927SAndroid Build Coastguard Worker#endif /* VULKAN */
1365*61046927SAndroid Build Coastguard Worker    }
1366*61046927SAndroid Build Coastguard Worker    else
1367*61046927SAndroid Build Coastguard Worker    {
1368*61046927SAndroid Build Coastguard Worker        uvec4 encoded;
1369*61046927SAndroid Build Coastguard Worker        if (block_mode.void_extent && decode_mode == MODE_HDR)
1370*61046927SAndroid Build Coastguard Worker            encoded = uvec4(final_color);
1371*61046927SAndroid Build Coastguard Worker        else
1372*61046927SAndroid Build Coastguard Worker            encoded = decode_fp16(final_color, decode_mode);
1373*61046927SAndroid Build Coastguard Worker#ifdef VULKAN
1374*61046927SAndroid Build Coastguard Worker        if (is_3Dimage)
1375*61046927SAndroid Build Coastguard Worker            imageStore(OutputImage3D, ivec3(coord.xy, gl_WorkGroupID.z), encoded);
1376*61046927SAndroid Build Coastguard Worker        else
1377*61046927SAndroid Build Coastguard Worker            imageStore(OutputImage2Darray, ivec3(coord.xy, gl_WorkGroupID.z), encoded);
1378*61046927SAndroid Build Coastguard Worker#else /* VULKAN */
1379*61046927SAndroid Build Coastguard Worker        imageStore(OutputImage, coord.xy, encoded);
1380*61046927SAndroid Build Coastguard Worker#endif /* VULKAN */
1381*61046927SAndroid Build Coastguard Worker    }
1382*61046927SAndroid Build Coastguard Worker}
1383