amd/common,radeonsi: Move gfx10_format_table to common.
[mesa.git] / src / amd / common / gfx10_format_table.py
1 #
2 # Copyright 2017 Advanced Micro Devices, Inc.
3 #
4 # Permission is hereby granted, free of charge, to any person obtaining a
5 # copy of this software and associated documentation files (the "Software"),
6 # to deal in the Software without restriction, including without limitation
7 # on the rights to use, copy, modify, merge, publish, distribute, sub
8 # license, and/or sell copies of the Software, and to permit persons to whom
9 # the Software is furnished to do so, subject to the following conditions:
10 #
11 # The above copyright notice and this permission notice (including the next
12 # paragraph) shall be included in all copies or substantial portions of the
13 # Software.
14 #
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 # FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18 # THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19 # DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 # USE OR OTHER DEALINGS IN THE SOFTWARE.
22 #
23 """
24 Script that generates the mapping from Gallium PIPE_FORMAT_xxx to gfx10
25 IMG_FORMAT_xxx enums.
26 """
27
28 from __future__ import absolute_import, division, print_function, unicode_literals
29
30 import json
31 import mako.template
32 import os
33 import re
34 import sys
35
36 AMD_REGISTERS = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), "../registers"))
37 UTIL_FORMAT = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), "../../util/format"))
38 sys.path.extend([AMD_REGISTERS, UTIL_FORMAT])
39
40 from regdb import Object, RegisterDatabase
41 from u_format_parse import *
42
43 # ----------------------------------------------------------------------------
44 # Hard-coded mappings
45
46 def hardcoded_format(hw_enum):
47 return Object(img_format=hw_enum, flags=[])
48
49 HARDCODED = {
50 'PIPE_FORMAT_Z32_FLOAT_S8X24_UINT': hardcoded_format('X24_8_32_FLOAT'),
51 'PIPE_FORMAT_Z24_UNORM_S8_UINT': hardcoded_format('8_24_UNORM'),
52 'PIPE_FORMAT_S8_UINT_Z24_UNORM': hardcoded_format('24_8_UNORM'),
53 'PIPE_FORMAT_Z32_UNORM': None,
54 'PIPE_FORMAT_Z16_UNORM_S8_UINT': None,
55
56 'PIPE_FORMAT_R9G9B9E5_FLOAT': hardcoded_format('5_9_9_9_FLOAT'),
57 'PIPE_FORMAT_R11G11B10_FLOAT': hardcoded_format('10_11_11_FLOAT'), # NOTE: full set of int/unorm/etc. exists
58
59 'PIPE_FORMAT_R8G8_B8G8_UNORM': hardcoded_format('GB_GR_UNORM'),
60 'PIPE_FORMAT_G8R8_B8R8_UNORM': hardcoded_format('GB_GR_UNORM'),
61
62 'PIPE_FORMAT_R8G8_R8B8_UNORM': hardcoded_format('BG_RG_UNORM'),
63 'PIPE_FORMAT_G8R8_G8B8_UNORM': hardcoded_format('BG_RG_UNORM'),
64
65 # These mixed channel types are not supported natively
66 'PIPE_FORMAT_R8SG8SB8UX8U_NORM': None,
67 'PIPE_FORMAT_R10SG10SB10SA2U_NORM': None,
68 'PIPE_FORMAT_R5SG5SB6U_NORM': None,
69
70 # Only R8G8_SRGB is supported, not L8A8_SRGB
71 'PIPE_FORMAT_L8A8_SRGB': None,
72
73 # S3TC
74 'PIPE_FORMAT_DXT1_RGB': hardcoded_format('BC1_UNORM'),
75 'PIPE_FORMAT_DXT1_RGBA': hardcoded_format('BC1_UNORM'),
76 'PIPE_FORMAT_DXT1_SRGB': hardcoded_format('BC1_SRGB'),
77 'PIPE_FORMAT_DXT1_SRGBA': hardcoded_format('BC1_SRGB'),
78 'PIPE_FORMAT_DXT3_RGBA': hardcoded_format('BC2_UNORM'),
79 'PIPE_FORMAT_DXT3_SRGBA': hardcoded_format('BC2_SRGB'),
80 'PIPE_FORMAT_DXT5_RGBA': hardcoded_format('BC3_UNORM'),
81 'PIPE_FORMAT_DXT5_SRGBA': hardcoded_format('BC3_SRGB'),
82
83 # RGTC
84 'PIPE_FORMAT_RGTC1_UNORM': hardcoded_format('BC4_UNORM'),
85 'PIPE_FORMAT_RGTC1_SNORM': hardcoded_format('BC4_SNORM'),
86 'PIPE_FORMAT_RGTC2_UNORM': hardcoded_format('BC5_UNORM'),
87 'PIPE_FORMAT_RGTC2_SNORM': hardcoded_format('BC5_SNORM'),
88 'PIPE_FORMAT_LATC1_UNORM': hardcoded_format('BC4_UNORM'),
89 'PIPE_FORMAT_LATC1_SNORM': hardcoded_format('BC4_SNORM'),
90 'PIPE_FORMAT_LATC2_UNORM': hardcoded_format('BC5_UNORM'),
91 'PIPE_FORMAT_LATC2_SNORM': hardcoded_format('BC5_SNORM'),
92
93 # BPTC
94 'PIPE_FORMAT_BPTC_RGB_UFLOAT': hardcoded_format('BC6_UFLOAT'),
95 'PIPE_FORMAT_BPTC_RGB_FLOAT': hardcoded_format('BC6_SFLOAT'),
96
97 'PIPE_FORMAT_BPTC_RGBA_UNORM': hardcoded_format('BC7_UNORM'),
98 'PIPE_FORMAT_BPTC_SRGBA': hardcoded_format('BC7_SRGB'),
99 }
100
101
102 # ----------------------------------------------------------------------------
103 # Main script
104
105 header_template = mako.template.Template("""\
106 // DO NOT EDIT -- AUTOMATICALLY GENERATED
107
108 #define FMT(_img_format, ...) \
109 { .img_format = V_008F0C_IMG_FORMAT_##_img_format, \
110 ##__VA_ARGS__ }
111
112 static const struct gfx10_format gfx10_format_table[PIPE_FORMAT_COUNT] = {
113 % for pipe_format, args in formats:
114 % if args is not None:
115 [${pipe_format}] = FMT(${args}),
116 % else:
117 /* ${pipe_format} is not supported */
118 % endif
119 % endfor
120 };
121 """)
122
123 class Gfx10Format(object):
124 RE_plain_channel = re.compile(r'X?([0-9]+)')
125
126 def __init__(self, enum_entry):
127 self.img_format = enum_entry.name[11:]
128 self.flags = getattr(enum_entry, 'flags', [])
129
130 code = self.img_format.split('_')
131
132 self.plain_chan_sizes = []
133 for i, chan_code in enumerate(code):
134 m = self.RE_plain_channel.match(chan_code)
135 if m is None:
136 break
137 self.plain_chan_sizes.append(int(m.group(1)))
138 # Keep the bit sizes in little-endian order
139 self.plain_chan_sizes.reverse()
140
141 self.code = code[i:]
142
143
144 class Gfx10FormatMapping(object):
145 def __init__(self, pipe_formats, gfx10_formats):
146 self.pipe_formats = pipe_formats
147 self.gfx10_formats = gfx10_formats
148
149 self.plain_gfx10_formats = dict(
150 (tuple(['_'.join(fmt.code)] + fmt.plain_chan_sizes), fmt)
151 for fmt in gfx10_formats if fmt.plain_chan_sizes
152 )
153
154 def map(self, fmt):
155 if fmt.layout == PLAIN:
156 chan_type = set([chan.type for chan in fmt.le_channels if chan.type != VOID])
157 chan_norm = set([chan.norm for chan in fmt.le_channels if chan.type != VOID])
158 chan_pure = set([chan.pure for chan in fmt.le_channels if chan.type != VOID])
159 if len(chan_type) > 1 or len(chan_norm) > 1 or len(chan_pure) > 1:
160 print(('Format {fmt.name} has inconsistent channel types: ' +
161 '{chan_type} {chan_norm} {chan_pure}')
162 .format(**locals()),
163 file=sys.stderr)
164 return None
165
166 chan_type = chan_type.pop()
167 chan_norm = chan_norm.pop()
168 chan_pure = chan_pure.pop()
169 chan_sizes = [chan.size for chan in fmt.le_channels if chan.size != 0]
170
171 extra_flags = []
172
173 if fmt.colorspace == SRGB:
174 assert chan_type == UNSIGNED and chan_norm
175 num_format = 'SRGB'
176 else:
177 if chan_type == UNSIGNED:
178 if chan_pure:
179 num_format = 'UINT'
180 elif chan_sizes[0] == 32:
181 # Shader-based work-around for 32-bit non-pure-integer
182 num_format = 'UINT'
183 extra_flags.append('buffers_only')
184 elif chan_norm:
185 num_format = 'UNORM'
186 else:
187 num_format = 'USCALED'
188 elif chan_type == SIGNED:
189 if chan_pure:
190 num_format = 'SINT'
191 elif chan_sizes[0] == 32:
192 # Shader-based work-around for 32-bit non-pure-integer
193 num_format = 'SINT'
194 extra_flags.append('buffers_only')
195 elif chan_norm:
196 num_format = 'SNORM'
197 else:
198 num_format = 'SSCALED'
199 elif chan_type == FLOAT:
200 num_format = 'FLOAT'
201
202 if chan_sizes[0] == 64:
203 # Shader-based work-around for doubles
204 if len(chan_sizes) % 2 == 1:
205 # 1 or 3 loads for 1 or 3 double channels
206 chan_sizes = [32, 32]
207 else:
208 # 1 or 2 loads for 2 or 4 double channels
209 chan_sizes = [32, 32, 32, 32]
210 extra_flags.append('buffers_only')
211 else:
212 # Shader-based work-around
213 assert chan_type == FIXED
214 assert chan_sizes[0] == 32
215 num_format = 'SINT'
216 extra_flags.append('buffers_only')
217
218 # These are not supported as render targets, so we don't support
219 # them as images either.
220 if (len(chan_sizes) == 3 and chan_sizes[0] in (8, 16, 32) and
221 chan_sizes[0] == chan_sizes[1]):
222 extra_flags.append('buffers_only')
223 if chan_sizes[0] in (8, 16):
224 # Shader-based work-around: one load per channel
225 chan_sizes = [chan_sizes[0]]
226
227 # Don't expose SRGB buffer formats
228 if 'buffers_only' in extra_flags and fmt.colorspace == SRGB:
229 return None
230
231 # Don't support 4_4 because it's not supported as render targets
232 # and it's useless in other cases.
233 if len(chan_sizes) == 2 and chan_sizes[0] == 4:
234 return None
235
236 key = tuple([num_format] + chan_sizes)
237 if key not in self.plain_gfx10_formats:
238 return None
239
240 gfx10_fmt = self.plain_gfx10_formats[key]
241 return Object(
242 img_format=gfx10_fmt.img_format,
243 flags=gfx10_fmt.flags + extra_flags,
244 )
245
246 return None
247
248
249 if __name__ == '__main__':
250 pipe_formats = parse(sys.argv[1])
251
252 with open(sys.argv[2], 'r') as filp:
253 db = RegisterDatabase.from_json(json.load(filp))
254
255 gfx10_formats = [Gfx10Format(entry) for entry in db.enum('IMG_FORMAT').entries]
256
257 mapping = Gfx10FormatMapping(pipe_formats, gfx10_formats)
258
259 formats = []
260 for fmt in pipe_formats:
261 if fmt.name in HARDCODED:
262 obj = HARDCODED[fmt.name]
263 else:
264 obj = mapping.map(fmt)
265
266 if obj is not None:
267 args = obj.img_format
268 if 'buffers_only' in obj.flags:
269 args += ', .buffers_only = 1'
270 else:
271 args = None
272 formats.append((fmt.name, args))
273
274 print(header_template.render(formats=formats))