1/*
2 * Copyright 2020 Valve Corporation
3 * SPDX-License-Identifier: MIT
4 *
5 * Authors:
6 *    Jonathan Marek <jonathan@marek.ca>
7 */
8
9#ifndef TU_UTIL_H
10#define TU_UTIL_H
11
12#include "tu_common.h"
13
14#include "util/u_math.h"
15#include "util/format/u_format_pack.h"
16#include "util/format/u_format_zs.h"
17#include "compiler/shader_enums.h"
18
19#include "vk_util.h"
20
21/* Whenever we generate an error, pass it through this function. Useful for
22 * debugging, where we can break on it. Only call at error site, not when
23 * propagating errors. Might be useful to plug in a stack trace here.
24 */
25
26VkResult
27__vk_startup_errorf(struct tu_instance *instance,
28                    VkResult error,
29                    bool force_print,
30                    const char *file,
31                    int line,
32                    const char *format,
33                    ...) PRINTFLIKE(6, 7);
34
35/* Prints startup errors if TU_DEBUG=startup is set or on a debug driver
36 * build.
37 */
38#define vk_startup_errorf(instance, error, format, ...) \
39   __vk_startup_errorf(instance, error, \
40                       instance->debug_flags & TU_DEBUG_STARTUP, \
41                       __FILE__, __LINE__, format, ##__VA_ARGS__)
42
43void
44__tu_finishme(const char *file, int line, const char *format, ...)
45   PRINTFLIKE(3, 4);
46
47/**
48 * Print a FINISHME message, including its source location.
49 */
50#define tu_finishme(format, ...)                                             \
51   do {                                                                      \
52      static bool reported = false;                                          \
53      if (!reported) {                                                       \
54         __tu_finishme(__FILE__, __LINE__, format, ##__VA_ARGS__);           \
55         reported = true;                                                    \
56      }                                                                      \
57   } while (0)
58
59#define tu_stub()                                                            \
60   do {                                                                      \
61      tu_finishme("stub %s", __func__);                                      \
62   } while (0)
63
64void
65tu_framebuffer_tiling_config(struct tu_framebuffer *fb,
66                             const struct tu_device *device,
67                             const struct tu_render_pass *pass);
68
69#define TU_STAGE_MASK ((1 << MESA_SHADER_STAGES) - 1)
70
71#define tu_foreach_stage(stage, stage_bits)                                  \
72   for (gl_shader_stage stage,                                               \
73        __tmp = (gl_shader_stage)((stage_bits) &TU_STAGE_MASK);              \
74        stage = __builtin_ffs(__tmp) - 1, __tmp; __tmp &= ~(1 << (stage)))
75
76static inline enum a3xx_msaa_samples
77tu_msaa_samples(uint32_t samples)
78{
79   assert(__builtin_popcount(samples) == 1);
80   return util_logbase2(samples);
81}
82
83static inline uint32_t
84tu6_stage2opcode(gl_shader_stage stage)
85{
86   if (stage == MESA_SHADER_FRAGMENT || stage == MESA_SHADER_COMPUTE)
87      return CP_LOAD_STATE6_FRAG;
88   return CP_LOAD_STATE6_GEOM;
89}
90
91static inline enum a6xx_state_block
92tu6_stage2texsb(gl_shader_stage stage)
93{
94   return SB6_VS_TEX + stage;
95}
96
97static inline enum a6xx_state_block
98tu6_stage2shadersb(gl_shader_stage stage)
99{
100   return SB6_VS_SHADER + stage;
101}
102
103static inline enum a3xx_rop_code
104tu6_rop(VkLogicOp op)
105{
106   /* note: hw enum matches the VK enum, but with the 4 bits reversed */
107   static const uint8_t lookup[] = {
108      [VK_LOGIC_OP_CLEAR]           = ROP_CLEAR,
109      [VK_LOGIC_OP_AND]             = ROP_AND,
110      [VK_LOGIC_OP_AND_REVERSE]     = ROP_AND_REVERSE,
111      [VK_LOGIC_OP_COPY]            = ROP_COPY,
112      [VK_LOGIC_OP_AND_INVERTED]    = ROP_AND_INVERTED,
113      [VK_LOGIC_OP_NO_OP]           = ROP_NOOP,
114      [VK_LOGIC_OP_XOR]             = ROP_XOR,
115      [VK_LOGIC_OP_OR]              = ROP_OR,
116      [VK_LOGIC_OP_NOR]             = ROP_NOR,
117      [VK_LOGIC_OP_EQUIVALENT]      = ROP_EQUIV,
118      [VK_LOGIC_OP_INVERT]          = ROP_INVERT,
119      [VK_LOGIC_OP_OR_REVERSE]      = ROP_OR_REVERSE,
120      [VK_LOGIC_OP_COPY_INVERTED]   = ROP_COPY_INVERTED,
121      [VK_LOGIC_OP_OR_INVERTED]     = ROP_OR_INVERTED,
122      [VK_LOGIC_OP_NAND]            = ROP_NAND,
123      [VK_LOGIC_OP_SET]             = ROP_SET,
124   };
125   assert(op < ARRAY_SIZE(lookup));
126   return lookup[op];
127}
128
129static inline bool
130tu6_primtype_line(enum pc_di_primtype type)
131{
132    switch(type) {
133    case DI_PT_LINELIST:
134    case DI_PT_LINESTRIP:
135    case DI_PT_LINE_ADJ:
136    case DI_PT_LINESTRIP_ADJ:
137       return true;
138    default:
139       return false;
140    }
141}
142
143static inline bool
144tu6_primtype_patches(enum pc_di_primtype type)
145{
146   return type >= DI_PT_PATCHES0 && type <= DI_PT_PATCHES31;
147}
148
149static inline enum pc_di_primtype
150tu6_primtype(VkPrimitiveTopology topology)
151{
152   static const uint8_t lookup[] = {
153      [VK_PRIMITIVE_TOPOLOGY_POINT_LIST]                    = DI_PT_POINTLIST,
154      [VK_PRIMITIVE_TOPOLOGY_LINE_LIST]                     = DI_PT_LINELIST,
155      [VK_PRIMITIVE_TOPOLOGY_LINE_STRIP]                    = DI_PT_LINESTRIP,
156      [VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST]                 = DI_PT_TRILIST,
157      [VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP]                = DI_PT_TRISTRIP,
158      [VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN]                  = DI_PT_TRIFAN,
159      [VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY]      = DI_PT_LINE_ADJ,
160      [VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY]     = DI_PT_LINESTRIP_ADJ,
161      [VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY]  = DI_PT_TRI_ADJ,
162      [VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY] = DI_PT_TRISTRIP_ADJ,
163      /* Return PATCH0 and update in tu_pipeline_builder_parse_tessellation */
164      [VK_PRIMITIVE_TOPOLOGY_PATCH_LIST]                    = DI_PT_PATCHES0,
165   };
166   assert(topology < ARRAY_SIZE(lookup));
167   return lookup[topology];
168}
169
170static inline enum adreno_compare_func
171tu6_compare_func(VkCompareOp op)
172{
173   return (enum adreno_compare_func) op;
174}
175
176static inline enum adreno_stencil_op
177tu6_stencil_op(VkStencilOp op)
178{
179   return (enum adreno_stencil_op) op;
180}
181
182static inline enum adreno_rb_blend_factor
183tu6_blend_factor(VkBlendFactor factor)
184{
185   static const uint8_t lookup[] = {
186      [VK_BLEND_FACTOR_ZERO]                    = FACTOR_ZERO,
187      [VK_BLEND_FACTOR_ONE]                     = FACTOR_ONE,
188      [VK_BLEND_FACTOR_SRC_COLOR]               = FACTOR_SRC_COLOR,
189      [VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR]     = FACTOR_ONE_MINUS_SRC_COLOR,
190      [VK_BLEND_FACTOR_DST_COLOR]               = FACTOR_DST_COLOR,
191      [VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR]     = FACTOR_ONE_MINUS_DST_COLOR,
192      [VK_BLEND_FACTOR_SRC_ALPHA]               = FACTOR_SRC_ALPHA,
193      [VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA]     = FACTOR_ONE_MINUS_SRC_ALPHA,
194      [VK_BLEND_FACTOR_DST_ALPHA]               = FACTOR_DST_ALPHA,
195      [VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA]     = FACTOR_ONE_MINUS_DST_ALPHA,
196      [VK_BLEND_FACTOR_CONSTANT_COLOR]          = FACTOR_CONSTANT_COLOR,
197      [VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR]= FACTOR_ONE_MINUS_CONSTANT_COLOR,
198      [VK_BLEND_FACTOR_CONSTANT_ALPHA]          = FACTOR_CONSTANT_ALPHA,
199      [VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA]= FACTOR_ONE_MINUS_CONSTANT_ALPHA,
200      [VK_BLEND_FACTOR_SRC_ALPHA_SATURATE]      = FACTOR_SRC_ALPHA_SATURATE,
201      [VK_BLEND_FACTOR_SRC1_COLOR]              = FACTOR_SRC1_COLOR,
202      [VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR]    = FACTOR_ONE_MINUS_SRC1_COLOR,
203      [VK_BLEND_FACTOR_SRC1_ALPHA]              = FACTOR_SRC1_ALPHA,
204      [VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA]    = FACTOR_ONE_MINUS_SRC1_ALPHA,
205   };
206   assert(factor < ARRAY_SIZE(lookup));
207   return lookup[factor];
208}
209
210static inline enum a3xx_rb_blend_opcode
211tu6_blend_op(VkBlendOp op)
212{
213   return (enum a3xx_rb_blend_opcode) op;
214}
215
216static inline enum a6xx_tex_type
217tu6_tex_type(VkImageViewType type, bool storage)
218{
219   switch (type) {
220   default:
221   case VK_IMAGE_VIEW_TYPE_1D:
222   case VK_IMAGE_VIEW_TYPE_1D_ARRAY:
223      return A6XX_TEX_1D;
224   case VK_IMAGE_VIEW_TYPE_2D:
225   case VK_IMAGE_VIEW_TYPE_2D_ARRAY:
226      return A6XX_TEX_2D;
227   case VK_IMAGE_VIEW_TYPE_3D:
228      return A6XX_TEX_3D;
229   case VK_IMAGE_VIEW_TYPE_CUBE:
230   case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:
231      return storage ? A6XX_TEX_2D : A6XX_TEX_CUBE;
232   }
233}
234
235static inline enum a6xx_tex_clamp
236tu6_tex_wrap(VkSamplerAddressMode address_mode)
237{
238   uint8_t lookup[] = {
239      [VK_SAMPLER_ADDRESS_MODE_REPEAT]                = A6XX_TEX_REPEAT,
240      [VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT]       = A6XX_TEX_MIRROR_REPEAT,
241      [VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE]         = A6XX_TEX_CLAMP_TO_EDGE,
242      [VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER]       = A6XX_TEX_CLAMP_TO_BORDER,
243      [VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE]  = A6XX_TEX_MIRROR_CLAMP,
244   };
245   assert(address_mode < ARRAY_SIZE(lookup));
246   return lookup[address_mode];
247}
248
249static inline enum a6xx_tex_filter
250tu6_tex_filter(VkFilter filter, unsigned aniso)
251{
252   switch (filter) {
253   case VK_FILTER_NEAREST:
254      return A6XX_TEX_NEAREST;
255   case VK_FILTER_LINEAR:
256      return aniso ? A6XX_TEX_ANISO : A6XX_TEX_LINEAR;
257   case VK_FILTER_CUBIC_EXT:
258      return A6XX_TEX_CUBIC;
259   default:
260      unreachable("illegal texture filter");
261      break;
262   }
263}
264
265static inline enum a6xx_reduction_mode
266tu6_reduction_mode(VkSamplerReductionMode reduction_mode)
267{
268   return (enum a6xx_reduction_mode) reduction_mode;
269}
270
271static inline enum a6xx_depth_format
272tu6_pipe2depth(VkFormat format)
273{
274   switch (format) {
275   case VK_FORMAT_D16_UNORM:
276      return DEPTH6_16;
277   case VK_FORMAT_X8_D24_UNORM_PACK32:
278   case VK_FORMAT_D24_UNORM_S8_UINT:
279      return DEPTH6_24_8;
280   case VK_FORMAT_D32_SFLOAT:
281   case VK_FORMAT_D32_SFLOAT_S8_UINT:
282   case VK_FORMAT_S8_UINT:
283      return DEPTH6_32;
284   default:
285      return ~0;
286   }
287}
288
289static inline enum a6xx_polygon_mode
290tu6_polygon_mode(VkPolygonMode mode)
291{
292   switch (mode) {
293   case VK_POLYGON_MODE_POINT:
294      return POLYMODE6_POINTS;
295   case VK_POLYGON_MODE_LINE:
296      return POLYMODE6_LINES;
297   case VK_POLYGON_MODE_FILL:
298      return POLYMODE6_TRIANGLES;
299   default:
300      unreachable("bad polygon mode");
301   }
302}
303
304struct bcolor_entry {
305   uint32_t fp32[4];
306   uint64_t ui16;
307   uint64_t si16;
308   uint64_t fp16;
309   uint16_t rgb565;
310   uint16_t rgb5a1;
311   uint16_t rgba4;
312   uint8_t __pad0[2];
313   uint32_t ui8;
314   uint32_t si8;
315   uint32_t rgb10a2;
316   uint32_t z24; /* also s8? */
317   uint64_t srgb;
318   uint8_t  __pad1[56];
319} __attribute__((aligned(128)));
320
321/* vulkan does not want clamping of integer clear values, differs from u_format
322 * see spec for VkClearColorValue
323 */
324static inline void
325pack_int8(uint32_t *dst, const uint32_t *val)
326{
327   *dst = (val[0] & 0xff) |
328          (val[1] & 0xff) << 8 |
329          (val[2] & 0xff) << 16 |
330          (val[3] & 0xff) << 24;
331}
332
333static inline void
334pack_int10_2(uint32_t *dst, const uint32_t *val)
335{
336   *dst = (val[0] & 0x3ff) |
337          (val[1] & 0x3ff) << 10 |
338          (val[2] & 0x3ff) << 20 |
339          (val[3] & 0x3)   << 30;
340}
341
342static inline void
343pack_int16(uint32_t *dst, const uint32_t *val)
344{
345   dst[0] = (val[0] & 0xffff) |
346            (val[1] & 0xffff) << 16;
347   dst[1] = (val[2] & 0xffff) |
348            (val[3] & 0xffff) << 16;
349}
350
351static inline void
352tu6_pack_border_color(struct bcolor_entry *bcolor, const VkClearColorValue *val, bool is_int)
353{
354   memcpy(bcolor->fp32, val, 4 * sizeof(float));
355   if (is_int) {
356      pack_int16((uint32_t*) &bcolor->fp16, val->uint32);
357      return;
358   }
359#define PACK_F(x, type) util_format_##type##_pack_rgba_float \
360   ( (uint8_t*) (&bcolor->x), 0, val->float32, 0, 1, 1)
361   PACK_F(ui16, r16g16b16a16_unorm);
362   PACK_F(si16, r16g16b16a16_snorm);
363   PACK_F(fp16, r16g16b16a16_float);
364   PACK_F(rgb565, r5g6b5_unorm);
365   PACK_F(rgb5a1, r5g5b5a1_unorm);
366   PACK_F(rgba4, r4g4b4a4_unorm);
367   PACK_F(ui8, r8g8b8a8_unorm);
368   PACK_F(si8, r8g8b8a8_snorm);
369   PACK_F(rgb10a2, r10g10b10a2_unorm);
370   util_format_z24x8_unorm_pack_z_float((uint8_t*) &bcolor->z24,
371                                        0, val->float32, 0, 1, 1);
372   PACK_F(srgb, r16g16b16a16_float); /* TODO: clamp? */
373#undef PACK_F
374}
375
376void
377tu_dbg_log_gmem_load_store_skips(struct tu_device *device);
378
379#define perf_debug(device, fmt, ...) do {                               \
380   if (unlikely((device)->instance->debug_flags & TU_DEBUG_PERF))       \
381      mesa_log(MESA_LOG_WARN, (MESA_LOG_TAG), (fmt), ##__VA_ARGS__);    \
382} while(0)
383
384#endif /* TU_UTIL_H */
385