1 /*
2 * Copyright 2016 Intel Corporation
3 * Copyright 2016 Broadcom
4 * Copyright 2020 Collabora, Ltd.
5 * Copyright 2024 Alyssa Rosenzweig
6 * SPDX-License-Identifier: MIT
7 */
8
9 #pragma once
10
11 #include "compiler/libcl/libcl.h"
12 #include "util/bitpack_helpers.h"
13
14 #ifndef __OPENCL_VERSION__
15 #include <inttypes.h>
16 #include <stdio.h>
17 #include "util/half_float.h"
18 #endif
19
20 #define __gen_unpack_float(x, y, z) uif(__gen_unpack_uint(x, y, z))
21 #define __gen_unpack_half(x, y, z) \
22 _mesa_half_to_float(__gen_unpack_uint(x, y, z))
23
24 static inline uint64_t
__gen_unpack_uint(CONST uint32_t * restrict cl,uint32_t start,uint32_t end)25 __gen_unpack_uint(CONST uint32_t *restrict cl, uint32_t start, uint32_t end)
26 {
27 uint64_t val = 0;
28 const int width = end - start + 1;
29 const uint64_t mask =
30 (width == 64) ? ~((uint64_t)0) : ((uint64_t)1 << width) - 1;
31
32 for (unsigned word = start / 32; word < (end / 32) + 1; word++) {
33 val |= ((uint64_t)cl[word]) << ((word - start / 32) * 32);
34 }
35
36 return (val >> (start % 32)) & mask;
37 }
38
39 /*
40 * LODs are 4:6 fixed point. We must clamp before converting to integers to
41 * avoid undefined behaviour for out-of-bounds inputs like +/- infinity.
42 */
43 static inline uint32_t
__gen_pack_lod(float f,uint32_t start,uint32_t end)44 __gen_pack_lod(float f, uint32_t start, uint32_t end)
45 {
46 uint32_t fixed = CLAMP(f * (1 << 6), 0 /* 0.0 */, 0x380 /* 14.0 */);
47 return util_bitpack_uint(fixed, start, end);
48 }
49
50 static inline float
__gen_unpack_lod(CONST uint32_t * restrict cl,uint32_t start,uint32_t end)51 __gen_unpack_lod(CONST uint32_t *restrict cl, uint32_t start, uint32_t end)
52 {
53 return ((float)__gen_unpack_uint(cl, start, end)) / (1 << 6);
54 }
55
56 static inline uint64_t
__gen_unpack_sint(CONST uint32_t * restrict cl,uint32_t start,uint32_t end)57 __gen_unpack_sint(CONST uint32_t *restrict cl, uint32_t start, uint32_t end)
58 {
59 int size = end - start + 1;
60 int64_t val = __gen_unpack_uint(cl, start, end);
61
62 return util_sign_extend(val, size);
63 }
64
65 static inline uint64_t
__gen_to_groups(uint32_t value,uint32_t group_size,uint32_t length)66 __gen_to_groups(uint32_t value, uint32_t group_size, uint32_t length)
67 {
68 /* Zero is not representable, clamp to minimum */
69 if (value == 0)
70 return 1;
71
72 /* Round up to the nearest number of groups */
73 uint32_t groups = DIV_ROUND_UP(value, group_size);
74
75 /* The 0 encoding means "all" */
76 if (groups == ((uint64_t)1) << length)
77 return 0;
78
79 /* Otherwise it's encoded as the identity */
80 assert(groups < (1u << length) && "out of bounds");
81 assert(groups >= 1 && "exhaustive");
82 return groups;
83 }
84
85 static inline uint64_t
__gen_from_groups(uint32_t value,uint32_t group_size,uint32_t length)86 __gen_from_groups(uint32_t value, uint32_t group_size, uint32_t length)
87 {
88 return group_size * (value ? value : (1 << length));
89 }
90
91 #define agx_pack(dst, T, name) \
92 for (struct AGX_##T name = {AGX_##T##_header}, \
93 *_loop_count = (GLOBAL void *)((uintptr_t)0); \
94 (uintptr_t)_loop_count < 1; ( \
95 { \
96 AGX_##T##_pack((GLOBAL uint32_t *)(dst), &name); \
97 _loop_count = (GLOBAL void *)(((uintptr_t)_loop_count) + 1); \
98 }))
99
100 #define agx_unpack(fp, src, T, name) \
101 struct AGX_##T name; \
102 AGX_##T##_unpack(fp, (CONST uint8_t *)(src), &name)
103
104 #define agx_print(fp, T, var, indent) AGX_##T##_print(fp, &(var), indent)
105
106 static inline void
agx_merge_helper(uint32_t * dst,const uint32_t * src,size_t bytes)107 agx_merge_helper(uint32_t *dst, const uint32_t *src, size_t bytes)
108 {
109 assert((bytes & 3) == 0);
110
111 for (unsigned i = 0; i < (bytes / 4); ++i)
112 dst[i] |= src[i];
113 }
114
115 #define agx_merge(packed1, packed2, type) \
116 agx_merge_helper((packed1).opaque, (packed2).opaque, AGX_##type##_LENGTH)
117
118 #if defined(NDEBUG) || defined(__OPENCL_VERSION__)
119 #define agx_genxml_validate_bounds(a, b, c)
120 #define agx_genxml_validate_mask(a, b, c, d, e) true
121 #define agx_genxml_validate_exact(a, b, c, d) true
122 #else
123 static inline void
agx_genxml_validate_bounds(const char * name,uint64_t value,uint64_t bound)124 agx_genxml_validate_bounds(const char *name, uint64_t value, uint64_t bound)
125 {
126 if (unlikely(value >= bound)) {
127 fprintf(stderr, "%s out-of-bounds, got 0x%" PRIx64 ", max %" PRIx64 "\n",
128 name, value, bound);
129
130 unreachable("Out-of-bounds pack");
131 }
132 }
133
134 static inline bool
agx_genxml_validate_mask(FILE * fp,const char * name,const void * cl_,uint32_t index,uint32_t bad_mask)135 agx_genxml_validate_mask(FILE *fp, const char *name, const void *cl_,
136 uint32_t index, uint32_t bad_mask)
137 {
138 const uint32_t *cl = (const uint32_t *)cl_;
139 uint32_t bad = cl[index] & bad_mask;
140
141 if (bad && fp != NULL) {
142 fprintf(
143 fp,
144 "XXX: Unknown field of %s unpacked at word %u got %X, bad mask %X\n",
145 name, index, cl[index], bad);
146 }
147
148 return bad == 0;
149 }
150
151 static bool
agx_genxml_validate_exact(FILE * fp,const char * name,uint64_t value,uint64_t exact)152 agx_genxml_validate_exact(FILE *fp, const char *name, uint64_t value,
153 uint64_t exact)
154 {
155 if (value != exact && fp != NULL) {
156 fprintf(fp, "XXX: Expected %s to equal %" PRIx64 " but got %" PRIx64 "\n",
157 name, value, exact);
158 }
159
160 return value == exact;
161 }
162
163 #endif
164
165 /* Everything after this is autogenerated from XML. Do not hand edit. */
166