xref: /aosp_15_r20/external/mesa3d/src/asahi/lib/agx_border.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright 2022 Alyssa Rosenzweig
3  * SPDX-License-Identifier: MIT
4  */
5 
6 #include "util/format/format_utils.h"
7 #include "util/format/u_format.h"
8 #include "util/half_float.h"
9 #include "agx_helpers.h"
10 #include "agx_pack.h"
11 
12 /*
13  * AGX allows the sampler descriptor to specify a custom border colour. The
14  * packing depends on the texture format (i.e. no
15  * customBorderColorWithoutFormat).
16  *
17  * Each channel is packed separately into 32-bit words. Pure integers are stored
18  * as-is. Pure floats are extended to 16-bit/32-bit as appropriate. Normalized
19  * formats are encoded as usual, except sRGB gets 4 extra bits.
20  *
21  * The texture descriptor swizzle is applied to the border colour. That swizzle
22  * includes the format swizzle. In effect, we want to encode the border colour
23  * like it would be encoded in memory, and then the swizzles work out
24  * for Vulkan.
25  */
26 
27 struct channel {
28    enum util_format_type type;
29    bool normalized;
30    unsigned size;
31 };
32 
33 static struct channel
get_channel_info(enum pipe_format format,unsigned channel)34 get_channel_info(enum pipe_format format, unsigned channel)
35 {
36    /* Compressed formats may have packing with no PIPE equivalent, handle
37     * specially.
38     */
39    switch (format) {
40    case PIPE_FORMAT_ETC2_R11_UNORM:
41    case PIPE_FORMAT_ETC2_RG11_UNORM:
42       return (struct channel){UTIL_FORMAT_TYPE_UNSIGNED, true, 11};
43 
44    case PIPE_FORMAT_ETC2_R11_SNORM:
45    case PIPE_FORMAT_ETC2_RG11_SNORM:
46       return (struct channel){UTIL_FORMAT_TYPE_SIGNED, true, 11};
47 
48    case PIPE_FORMAT_RGTC1_UNORM:
49    case PIPE_FORMAT_RGTC2_UNORM:
50       return (struct channel){UTIL_FORMAT_TYPE_UNSIGNED, true, 14};
51    case PIPE_FORMAT_RGTC1_SNORM:
52    case PIPE_FORMAT_RGTC2_SNORM:
53       return (struct channel){UTIL_FORMAT_TYPE_SIGNED, true, 14};
54 
55    case PIPE_FORMAT_ETC1_RGB8:
56    case PIPE_FORMAT_ETC2_RGB8:
57    case PIPE_FORMAT_ETC2_RGBA8:
58    case PIPE_FORMAT_ETC2_RGB8A1:
59    case PIPE_FORMAT_BPTC_RGBA_UNORM:
60    case PIPE_FORMAT_DXT1_RGB:
61    case PIPE_FORMAT_DXT1_RGBA:
62    case PIPE_FORMAT_DXT3_RGBA:
63    case PIPE_FORMAT_DXT5_RGBA:
64       return (struct channel){UTIL_FORMAT_TYPE_UNSIGNED, true, 8};
65 
66    case PIPE_FORMAT_ETC2_SRGB8:
67    case PIPE_FORMAT_ETC2_SRGBA8:
68    case PIPE_FORMAT_ETC2_SRGB8A1:
69    case PIPE_FORMAT_BPTC_SRGBA:
70    case PIPE_FORMAT_DXT1_SRGB:
71    case PIPE_FORMAT_DXT1_SRGBA:
72    case PIPE_FORMAT_DXT3_SRGBA:
73    case PIPE_FORMAT_DXT5_SRGBA:
74       return (struct channel){
75          UTIL_FORMAT_TYPE_UNSIGNED,
76          true,
77          channel == 3 ? 8 : 12,
78       };
79 
80    case PIPE_FORMAT_BPTC_RGB_FLOAT:
81    case PIPE_FORMAT_BPTC_RGB_UFLOAT:
82       return (struct channel){UTIL_FORMAT_TYPE_FLOAT, false, 16};
83 
84    default:
85       assert(
86          !util_format_is_compressed(format) &&
87          "Other compressed formats must be special cased for border colours."
88          "Add more cases if we have a use case");
89 
90       break;
91    }
92 
93    const struct util_format_description *desc = util_format_description(format);
94    struct util_format_channel_description chan_desc = desc->channel[channel];
95    bool srgb = (desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) &&
96                (desc->swizzle[channel] <= PIPE_SWIZZLE_Z);
97 
98    if (chan_desc.type == UTIL_FORMAT_TYPE_UNSIGNED ||
99        chan_desc.type == UTIL_FORMAT_TYPE_SIGNED) {
100 
101       assert((chan_desc.normalized ^ chan_desc.pure_integer) &&
102              "no SCALED formats supported for texturing");
103    }
104 
105    if (srgb && chan_desc.type != UTIL_FORMAT_TYPE_VOID) {
106       assert(chan_desc.normalized && chan_desc.size == 8 &&
107              chan_desc.type == UTIL_FORMAT_TYPE_UNSIGNED &&
108              "only 8-bit unorm supported with sRGB");
109    }
110 
111    return (struct channel){
112       .type = chan_desc.type,
113       .normalized = chan_desc.normalized,
114       .size = srgb ? 12 : chan_desc.size,
115    };
116 }
117 
118 static uint32_t
pack_channel(uint32_t value,enum pipe_format format,unsigned channel)119 pack_channel(uint32_t value, enum pipe_format format, unsigned channel)
120 {
121    struct channel chan = get_channel_info(format, channel);
122 
123    switch (chan.type) {
124    case UTIL_FORMAT_TYPE_VOID:
125       return 0;
126 
127    case UTIL_FORMAT_TYPE_UNSIGNED:
128       if (chan.normalized)
129          return _mesa_float_to_unorm(uif(value), chan.size);
130       else
131          return _mesa_unsigned_to_unsigned(value, chan.size);
132 
133    case UTIL_FORMAT_TYPE_SIGNED:
134       if (chan.normalized)
135          return _mesa_float_to_snorm(uif(value), chan.size);
136       else
137          return _mesa_signed_to_signed(value, chan.size);
138 
139    case UTIL_FORMAT_TYPE_FLOAT:
140       assert(chan.size == 32 || chan.size <= 16);
141       return chan.size == 32 ? value : _mesa_float_to_half(uif(value));
142 
143    case UTIL_FORMAT_TYPE_FIXED:
144       unreachable("no FIXED textures");
145    }
146 
147    unreachable("invalid format type");
148 }
149 
150 void
agx_pack_border(struct agx_border_packed * out,const uint32_t in[4],enum pipe_format format)151 agx_pack_border(struct agx_border_packed *out, const uint32_t in[4],
152                 enum pipe_format format)
153 {
154    assert(format != PIPE_FORMAT_NONE);
155 
156    const struct util_format_description *desc = util_format_description(format);
157    uint8_t channel_map[4] = {0};
158 
159    /* Determine the in-memory order of the format. That is the inverse of the
160     * format swizzle. If a component is replicated, we use the first component,
161     * by looping backwards and overwriting.
162     */
163    for (int i = 3; i >= 0; --i) {
164       static_assert(PIPE_SWIZZLE_X == 0, "known ordering");
165       static_assert(PIPE_SWIZZLE_W == 3, "known ordering");
166 
167       if (desc->swizzle[i] <= PIPE_SWIZZLE_W)
168          channel_map[i] = desc->swizzle[i];
169    }
170 
171    agx_pack(out, BORDER, cfg) {
172       cfg.channel_0 = pack_channel(in[channel_map[0]], format, 0);
173       cfg.channel_1 = pack_channel(in[channel_map[1]], format, 1);
174       cfg.channel_2 = pack_channel(in[channel_map[2]], format, 2);
175       cfg.channel_3 = pack_channel(in[channel_map[3]], format, 3);
176    }
177 }
178