1# encoding=utf-8 2# Copyright © 2016 Intel Corporation 3 4# Permission is hereby granted, free of charge, to any person obtaining a copy 5# of this software and associated documentation files (the "Software"), to deal 6# in the Software without restriction, including without limitation the rights 7# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8# copies of the Software, and to permit persons to whom the Software is 9# furnished to do so, subject to the following conditions: 10 11# The above copyright notice and this permission notice shall be included in 12# all copies or substantial portions of the Software. 13 14# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20# SOFTWARE. 21 22"""Generates isl_format_layout.c.""" 23 24import argparse 25import csv 26import re 27 28from mako import template 29 30# Load the template and set the bytes encoding to be utf-8. 31TEMPLATE = template.Template(text="""\ 32/* This file is autogenerated by gen_format_layout.py. DO NOT EDIT! */ 33 34/* 35 * Copyright 2015 Intel Corporation 36 * 37 * Permission is hereby granted, free of charge, to any person obtaining a 38 * copy of this software and associated documentation files (the "Software"), 39 * to deal in the Software without restriction, including without limitation 40 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 41 * and/or sell copies of the Software, and to permit persons to whom the 42 * Software is furnished to do so, subject to the following conditions: 43 * 44 * The above copyright notice and this permission notice (including the next 45 * paragraph) shall be included in all copies or substantial portions of the 46 * Software. 47 * 48 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 49 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 50 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 51 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 52 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 53 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 54 * IN THE SOFTWARE. 55 */ 56 57#include "isl/isl.h" 58 59const uint16_t isl_format_name_offsets[] = { <% offset = 0 %> 60% for format in formats: 61 [ISL_FORMAT_${format.name}] = ${offset}, <% offset += 11 + len(format.name) + 1 %> 62% endfor 63}; 64 65const char isl_format_names[] = { 66% for format in formats: 67 "ISL_FORMAT_${format.name}\\0" 68% endfor 69}; 70 71const struct isl_format_layout 72isl_format_layouts[] = { 73% for format in formats: 74 [ISL_FORMAT_${format.name}] = { 75 .format = ISL_FORMAT_${format.name}, 76 .bpb = ${format.bpb}, 77 .bw = ${format.bw}, 78 .bh = ${format.bh}, 79 .bd = ${format.bd}, 80 .channels = { 81 % for mask in ['r', 'g', 'b', 'a', 'l', 'i', 'p']: 82 <% channel = getattr(format, mask, None) %>\\ 83 % if channel.type is not None: 84 .${mask} = { ISL_${channel.type}, ${channel.start}, ${channel.size} }, 85 % else: 86 .${mask} = {}, 87 % endif 88 % endfor 89 }, 90 .uniform_channel_type = ISL_${format.uniform_channel_type}, 91 .colorspace = ISL_COLORSPACE_${format.colorspace}, 92 .txc = ISL_TXC_${format.txc}, 93 }, 94 95% endfor 96}; 97 98bool 99isl_format_is_valid(enum isl_format format) 100{ 101 if (format >= sizeof(isl_format_layouts) / sizeof(isl_format_layouts[0])) 102 return false; 103 104 /* Only ISL_FORMAT_R32G32B32A32_FLOAT == 0 but that's a valid format. 105 * For all others, if this doesn't match then the entry in the table 106 * must not exist. 107 */ 108 return isl_format_layouts[format].format == format; 109} 110 111enum isl_format 112isl_format_srgb_to_linear(enum isl_format format) 113{ 114 switch (format) { 115% for srgb, rgb in srgb_to_linear_map: 116 case ISL_FORMAT_${srgb}: 117 return ISL_FORMAT_${rgb}; 118%endfor 119 default: 120 return format; 121 } 122} 123""") 124 125 126class Channel(object): 127 """Class representing a Channel. 128 129 Converts the csv encoded data into the format that the template (and thus 130 the consuming C code) expects. 131 132 """ 133 # If the csv file grew very large this class could be put behind a factory 134 # to increase efficiency. Right now though it's fast enough that It didn't 135 # seem worthwhile to add all of the boilerplate 136 _types = { 137 'x': 'void', 138 'r': 'raw', 139 'un': 'unorm', 140 'sn': 'snorm', 141 'uf': 'ufloat', 142 'sf': 'sfloat', 143 'ux': 'ufixed', 144 'sx': 'sfixed', 145 'ui': 'uint', 146 'si': 'sint', 147 'us': 'uscaled', 148 'ss': 'sscaled', 149 } 150 _splitter = re.compile(r'\s*(?P<type>[a-z]+)(?P<size>[0-9]+)') 151 152 def __init__(self, line): 153 # If the line is just whitespace then just set everything to None to 154 # save on the regex cost and let the template skip on None. 155 if line.isspace(): 156 self.size = None 157 self.type = None 158 else: 159 grouped = self._splitter.match(line) 160 self.type = self._types[grouped.group('type')].upper() 161 self.size = int(grouped.group('size')) 162 163 # Default the start bit to -1 164 self.start = -1 165 166 167class Format(object): 168 """Class that contains all values needed by the template.""" 169 def __init__(self, line): 170 # pylint: disable=invalid-name 171 self.name = line[0].strip() 172 173 self.bpb = int(line[1]) 174 self.bw = line[2].strip() 175 self.bh = line[3].strip() 176 self.bd = line[4].strip() 177 self.r = Channel(line[5]) 178 self.g = Channel(line[6]) 179 self.b = Channel(line[7]) 180 self.a = Channel(line[8]) 181 self.l = Channel(line[9]) 182 self.i = Channel(line[10]) 183 self.p = Channel(line[11]) 184 185 # Set the start bit value for each channel 186 self.order = line[12].strip() 187 bit = 0 188 for c in self.order: 189 chan = getattr(self, c) 190 chan.start = bit 191 bit = bit + chan.size 192 193 # Set the uniform channel type, if the format has one. 194 # 195 # Iterate over all channels, not just those in self.order, because 196 # some formats have an empty 'order' field in the CSV (such as 197 # YCRCB_NORMAL). 198 self.uniform_channel_type = 'VOID' 199 for chan in self.channels: 200 if chan.type in (None, 'VOID'): 201 pass 202 elif self.uniform_channel_type == 'VOID': 203 self.uniform_channel_type = chan.type 204 elif self.uniform_channel_type == chan.type: 205 pass 206 else: 207 self.uniform_channel_type = 'VOID' 208 break 209 210 # alpha doesn't have a colorspace of it's own. 211 self.colorspace = line[13].strip().upper() 212 if self.colorspace in ['']: 213 self.colorspace = 'NONE' 214 215 # This sets it to the line value, or if it's an empty string 'NONE' 216 self.txc = line[14].strip().upper() or 'NONE' 217 218 219 @property 220 def channels(self): 221 yield self.r 222 yield self.g 223 yield self.b 224 yield self.a 225 yield self.l 226 yield self.i 227 yield self.p 228 229 230def reader(csvfile): 231 """Wrapper around csv.reader that skips comments and blanks.""" 232 # csv.reader actually reads the file one line at a time (it was designed to 233 # open excel generated sheets), so hold the file until all of the lines are 234 # read. 235 with open(csvfile, 'r') as f: 236 for line in csv.reader(f): 237 if line and not line[0].startswith('#'): 238 yield line 239 240def get_srgb_to_linear_map(formats): 241 """Compute a map from sRGB to linear formats. 242 243 This function uses some probably somewhat fragile string munging to do 244 the conversion. However, we do assert that, if it's SRGB, the munging 245 succeeded so that gives some safety. 246 """ 247 names = {f.name for f in formats} 248 for fmt in formats: 249 if fmt.colorspace != 'SRGB': 250 continue 251 252 replacements = [ 253 ('_SRGB', ''), 254 ('SRGB', 'RGB'), 255 ('U8SRGB', 'FLT16'), 256 ] 257 258 found = False 259 for rep in replacements: 260 rgb_name = fmt.name.replace(rep[0], rep[1]) 261 if rgb_name in names: 262 found = True 263 yield fmt.name, rgb_name 264 break 265 266 # We should have found a format name 267 assert found 268 269def main(): 270 """Main function.""" 271 parser = argparse.ArgumentParser() 272 parser.add_argument('--csv', action='store', help='The CSV file to parse.') 273 parser.add_argument( 274 '--out', 275 action='store', 276 help='The location to put the generated C file.') 277 args = parser.parse_args() 278 279 # This generator opens and writes the file itself, and it does so in bytes 280 # mode. This solves the locale problem: Unicode can be rendered even 281 # if the shell calling this script doesn't. 282 with open(args.out, 'w') as f: 283 formats = [Format(l) for l in reader(args.csv)] 284 try: 285 # This basically does lazy evaluation and initialization, which 286 # saves on memory and startup overhead. 287 f.write(TEMPLATE.render( 288 formats = formats, 289 srgb_to_linear_map = list(get_srgb_to_linear_map(formats)), 290 )) 291 except Exception: 292 # In the even there's an error this imports some helpers from mako 293 # to print a useful stack trace and prints it, then exits with 294 # status 1, if python is run with debug; otherwise it just raises 295 # the exception 296 if __debug__: 297 import sys 298 from mako import exceptions 299 print(exceptions.text_error_template().render(), 300 file=sys.stderr) 301 sys.exit(1) 302 raise 303 304 305if __name__ == '__main__': 306 main() 307