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""" 24Script that generates the mapping from Gallium PIPE_FORMAT_xxx to GFX10_FORMAT_xxx enums. 25""" 26 27import json 28import mako.template 29import os 30import re 31import sys 32 33AMD_REGISTERS = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), "../registers")) 34UTIL_FORMAT = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), "../../util/format")) 35sys.path.extend([AMD_REGISTERS, UTIL_FORMAT]) 36 37from regdb import Object, RegisterDatabase 38from u_format_parse import * 39 40# ---------------------------------------------------------------------------- 41# Hard-coded mappings 42 43def hardcoded_format(hw_enum): 44 return Object(img_format=hw_enum, flags=[]) 45 46HARDCODED = { 47 'PIPE_FORMAT_Z32_FLOAT_S8X24_UINT': hardcoded_format('X24_8_32_FLOAT'), 48 'PIPE_FORMAT_Z24_UNORM_S8_UINT': hardcoded_format('8_24_UNORM'), 49 'PIPE_FORMAT_S8_UINT_Z24_UNORM': hardcoded_format('24_8_UNORM'), 50 'PIPE_FORMAT_Z32_UNORM': None, 51 'PIPE_FORMAT_Z16_UNORM_S8_UINT': None, 52 53 'PIPE_FORMAT_R9G9B9E5_FLOAT': hardcoded_format('5_9_9_9_FLOAT'), 54 'PIPE_FORMAT_R11G11B10_FLOAT': hardcoded_format('10_11_11_FLOAT'), # NOTE: full set of int/unorm/etc. exists 55 56 'PIPE_FORMAT_R8G8_B8G8_UNORM': hardcoded_format('GB_GR_UNORM'), 57 'PIPE_FORMAT_G8R8_B8R8_UNORM': hardcoded_format('GB_GR_UNORM'), 58 59 'PIPE_FORMAT_R8G8_R8B8_UNORM': hardcoded_format('BG_RG_UNORM'), 60 'PIPE_FORMAT_G8R8_G8B8_UNORM': hardcoded_format('BG_RG_UNORM'), 61 62 # These mixed channel types are not supported natively 63 'PIPE_FORMAT_R8SG8SB8UX8U_NORM': None, 64 'PIPE_FORMAT_R10SG10SB10SA2U_NORM': None, 65 'PIPE_FORMAT_R5SG5SB6U_NORM': None, 66 67 # Only R8G8_SRGB is supported, not L8A8_SRGB 68 'PIPE_FORMAT_L8A8_SRGB': None, 69 70 # S3TC 71 'PIPE_FORMAT_DXT1_RGB': hardcoded_format('BC1_UNORM'), 72 'PIPE_FORMAT_DXT1_RGBA': hardcoded_format('BC1_UNORM'), 73 'PIPE_FORMAT_DXT1_SRGB': hardcoded_format('BC1_SRGB'), 74 'PIPE_FORMAT_DXT1_SRGBA': hardcoded_format('BC1_SRGB'), 75 'PIPE_FORMAT_DXT3_RGBA': hardcoded_format('BC2_UNORM'), 76 'PIPE_FORMAT_DXT3_SRGBA': hardcoded_format('BC2_SRGB'), 77 'PIPE_FORMAT_DXT5_RGBA': hardcoded_format('BC3_UNORM'), 78 'PIPE_FORMAT_DXT5_SRGBA': hardcoded_format('BC3_SRGB'), 79 80 # RGTC 81 'PIPE_FORMAT_RGTC1_UNORM': hardcoded_format('BC4_UNORM'), 82 'PIPE_FORMAT_RGTC1_SNORM': hardcoded_format('BC4_SNORM'), 83 'PIPE_FORMAT_RGTC2_UNORM': hardcoded_format('BC5_UNORM'), 84 'PIPE_FORMAT_RGTC2_SNORM': hardcoded_format('BC5_SNORM'), 85 'PIPE_FORMAT_LATC1_UNORM': hardcoded_format('BC4_UNORM'), 86 'PIPE_FORMAT_LATC1_SNORM': hardcoded_format('BC4_SNORM'), 87 'PIPE_FORMAT_LATC2_UNORM': hardcoded_format('BC5_UNORM'), 88 'PIPE_FORMAT_LATC2_SNORM': hardcoded_format('BC5_SNORM'), 89 90 # BPTC 91 'PIPE_FORMAT_BPTC_RGB_UFLOAT': hardcoded_format('BC6_UFLOAT'), 92 'PIPE_FORMAT_BPTC_RGB_FLOAT': hardcoded_format('BC6_SFLOAT'), 93 94 'PIPE_FORMAT_BPTC_RGBA_UNORM': hardcoded_format('BC7_UNORM'), 95 'PIPE_FORMAT_BPTC_SRGBA': hardcoded_format('BC7_SRGB'), 96 97 'PIPE_FORMAT_R64_UINT': hardcoded_format('32_32_UINT'), 98 'PIPE_FORMAT_R64_SINT': hardcoded_format('32_32_SINT'), 99} 100 101 102# ---------------------------------------------------------------------------- 103# Main script 104 105header_template = mako.template.Template("""\ 106% if header: 107// DO NOT EDIT -- AUTOMATICALLY GENERATED 108 109#include "gfx10_format_table.h" 110#include "amdgfxregs.h" 111 112% endif 113 114#define FMT(_img_format, ...) \ 115 { .img_format = V_008F0C_${gfx.upper()}_FORMAT_##_img_format, \ 116 ##__VA_ARGS__ } 117 118const struct gfx10_format ${gfx}_format_table[PIPE_FORMAT_COUNT] = { 119% for pipe_format, args in formats: 120 % if args is not None: 121 [${pipe_format}] = FMT(${args}), 122 % else: 123/* ${pipe_format} is not supported */ 124 % endif 125% endfor 126 127#undef FMT 128}; 129""") 130 131class Gfx10Format(object): 132 RE_plain_channel = re.compile(r'X?([0-9]+)') 133 134 def __init__(self, enum_entry): 135 self.img_format = enum_entry.name[13:] 136 self.flags = getattr(enum_entry, 'flags', []) 137 138 code = self.img_format.split('_') 139 140 self.plain_chan_sizes = [] 141 for i, chan_code in enumerate(code): 142 m = self.RE_plain_channel.match(chan_code) 143 if m is None: 144 break 145 self.plain_chan_sizes.append(int(m.group(1))) 146 # Keep the bit sizes in little-endian order 147 self.plain_chan_sizes.reverse() 148 149 self.code = code[i:] 150 151 152class Gfx10FormatMapping(object): 153 def __init__(self, pipe_formats, gfx10_formats): 154 self.pipe_formats = pipe_formats 155 self.gfx10_formats = gfx10_formats 156 157 self.plain_gfx10_formats = dict( 158 (tuple(['_'.join(fmt.code)] + fmt.plain_chan_sizes), fmt) 159 for fmt in gfx10_formats if fmt.plain_chan_sizes 160 ) 161 162 def map(self, fmt): 163 if fmt.layout == PLAIN: 164 chan_type = set([chan.type for chan in fmt.le_channels if chan.type != VOID]) 165 chan_norm = set([chan.norm for chan in fmt.le_channels if chan.type != VOID]) 166 chan_pure = set([chan.pure for chan in fmt.le_channels if chan.type != VOID]) 167 if len(chan_type) > 1 or len(chan_norm) > 1 or len(chan_pure) > 1: 168 print(('Format {fmt.name} has inconsistent channel types: ' + 169 '{chan_type} {chan_norm} {chan_pure}') 170 .format(**locals()), 171 file=sys.stderr) 172 return None 173 174 chan_type = chan_type.pop() 175 chan_norm = chan_norm.pop() 176 chan_pure = chan_pure.pop() 177 chan_sizes = [chan.size for chan in fmt.le_channels if chan.size != 0] 178 179 extra_flags = [] 180 181 if fmt.colorspace == SRGB: 182 assert chan_type == UNSIGNED and chan_norm 183 num_format = 'SRGB' 184 else: 185 if chan_type == UNSIGNED: 186 if chan_pure: 187 num_format = 'UINT' 188 elif chan_sizes[0] == 32: 189 # Shader-based work-around for 32-bit non-pure-integer 190 num_format = 'UINT' 191 extra_flags.append('buffers_only') 192 elif chan_norm: 193 num_format = 'UNORM' 194 else: 195 num_format = 'USCALED' 196 extra_flags.append('buffers_only') 197 elif chan_type == SIGNED: 198 if chan_pure: 199 num_format = 'SINT' 200 elif chan_sizes[0] == 32: 201 # Shader-based work-around for 32-bit non-pure-integer 202 num_format = 'SINT' 203 extra_flags.append('buffers_only') 204 elif chan_norm: 205 num_format = 'SNORM' 206 else: 207 num_format = 'SSCALED' 208 extra_flags.append('buffers_only') 209 elif chan_type == FLOAT: 210 num_format = 'FLOAT' 211 212 if chan_sizes[0] == 64: 213 # Shader-based work-around for doubles 214 if len(chan_sizes) % 2 == 1: 215 # 1 or 3 loads for 1 or 3 double channels 216 chan_sizes = [32, 32] 217 else: 218 # 1 or 2 loads for 2 or 4 double channels 219 chan_sizes = [32, 32, 32, 32] 220 extra_flags.append('buffers_only') 221 else: 222 # Shader-based work-around 223 assert chan_type == FIXED 224 assert chan_sizes[0] == 32 225 num_format = 'SINT' 226 extra_flags.append('buffers_only') 227 228 # These are not supported as render targets, so we don't support 229 # them as images either. 230 if (len(chan_sizes) == 3 and chan_sizes[0] in (8, 16, 32) and 231 chan_sizes[0] == chan_sizes[1]): 232 extra_flags.append('buffers_only') 233 if chan_sizes[0] in (8, 16): 234 # Shader-based work-around: one load per channel 235 chan_sizes = [chan_sizes[0]] 236 237 # Don't expose SRGB buffer formats 238 if 'buffers_only' in extra_flags and fmt.colorspace == SRGB: 239 return None 240 241 # Don't support 4_4 because it's not supported as render targets 242 # and it's useless in other cases. 243 if len(chan_sizes) == 2 and chan_sizes[0] == 4: 244 return None 245 246 key = tuple([num_format] + chan_sizes) 247 if key not in self.plain_gfx10_formats: 248 return None 249 250 gfx10_fmt = self.plain_gfx10_formats[key] 251 return Object( 252 img_format=gfx10_fmt.img_format, 253 flags=gfx10_fmt.flags + extra_flags, 254 ) 255 256 return None 257 258def pipe_formats_to_formats(pipe_formats, mapping): 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 return formats 275 276if __name__ == '__main__': 277 pipe_formats = parse(sys.argv[1]) 278 279 # gfx10 280 with open(sys.argv[2], 'r') as filp: 281 db = RegisterDatabase.from_json(json.load(filp)) 282 283 gfx10_formats = [Gfx10Format(entry) for entry in db.enum('GFX10_FORMAT').entries] 284 mapping = Gfx10FormatMapping(pipe_formats, gfx10_formats) 285 formats = pipe_formats_to_formats(pipe_formats, mapping) 286 print(header_template.render(header=True, gfx='gfx10', formats=formats)) 287 288 # gfx11 289 with open(sys.argv[3], 'r') as filp: 290 db = RegisterDatabase.from_json(json.load(filp)) 291 292 gfx11_formats = [Gfx10Format(entry) for entry in db.enum('GFX11_FORMAT').entries] 293 mapping = Gfx10FormatMapping(pipe_formats, gfx11_formats) 294 formats = pipe_formats_to_formats(pipe_formats, mapping) 295 print(header_template.render(header=False, gfx='gfx11', formats=formats)) 296