• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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