310 lines
10 KiB
Python
310 lines
10 KiB
Python
# encoding=utf-8
|
|
# Copyright © 2016 Intel Corporation
|
|
|
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
# of this software and associated documentation files (the "Software"), to deal
|
|
# in the Software without restriction, including without limitation the rights
|
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
# copies of the Software, and to permit persons to whom the Software is
|
|
# furnished to do so, subject to the following conditions:
|
|
|
|
# The above copyright notice and this permission notice shall be included in
|
|
# all copies or substantial portions of the Software.
|
|
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
# SOFTWARE.
|
|
|
|
"""Generates isl_format_layout.c."""
|
|
|
|
import argparse
|
|
import csv
|
|
import re
|
|
|
|
from mako import template
|
|
|
|
# Load the template and set the bytes encoding to be utf-8.
|
|
TEMPLATE = template.Template(output_encoding='utf-8',
|
|
text="""\
|
|
/* This file is autogenerated by gen_format_layout.py. DO NOT EDIT! */
|
|
|
|
/*
|
|
* Copyright 2015 Intel Corporation
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice (including the next
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
|
* Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
* IN THE SOFTWARE.
|
|
*/
|
|
|
|
#include "isl/isl.h"
|
|
|
|
const uint16_t isl_format_name_offsets[] = { <% offset = 0 %>
|
|
% for format in formats:
|
|
[ISL_FORMAT_${format.name}] = ${offset}, <% offset += 11 + len(format.name) + 1 %>
|
|
% endfor
|
|
};
|
|
|
|
const char isl_format_names[] = {
|
|
% for format in formats:
|
|
"ISL_FORMAT_${format.name}\\0"
|
|
% endfor
|
|
};
|
|
|
|
const struct isl_format_layout
|
|
isl_format_layouts[] = {
|
|
% for format in formats:
|
|
[ISL_FORMAT_${format.name}] = {
|
|
.format = ISL_FORMAT_${format.name},
|
|
.bpb = ${format.bpb},
|
|
.bw = ${format.bw},
|
|
.bh = ${format.bh},
|
|
.bd = ${format.bd},
|
|
.channels = {
|
|
% for mask in ['r', 'g', 'b', 'a', 'l', 'i', 'p']:
|
|
<% channel = getattr(format, mask, None) %>\\
|
|
% if channel.type is not None:
|
|
.${mask} = { ISL_${channel.type}, ${channel.start}, ${channel.size} },
|
|
% else:
|
|
.${mask} = {},
|
|
% endif
|
|
% endfor
|
|
},
|
|
.uniform_channel_type = ISL_${format.uniform_channel_type},
|
|
.colorspace = ISL_COLORSPACE_${format.colorspace},
|
|
.txc = ISL_TXC_${format.txc},
|
|
},
|
|
|
|
% endfor
|
|
};
|
|
|
|
bool
|
|
isl_format_is_valid(enum isl_format format)
|
|
{
|
|
if (format >= sizeof(isl_format_layouts) / sizeof(isl_format_layouts[0]))
|
|
return false;
|
|
|
|
/* Only ISL_FORMAT_R32G32B32A32_FLOAT == 0 but that's a valid format.
|
|
* For all others, if this doesn't match then the entry in the table
|
|
* must not exist.
|
|
*/
|
|
return isl_format_layouts[format].format == format;
|
|
}
|
|
|
|
enum isl_format
|
|
isl_format_srgb_to_linear(enum isl_format format)
|
|
{
|
|
switch (format) {
|
|
% for srgb, rgb in srgb_to_linear_map:
|
|
case ISL_FORMAT_${srgb}:
|
|
return ISL_FORMAT_${rgb};
|
|
%endfor
|
|
default:
|
|
return format;
|
|
}
|
|
}
|
|
""")
|
|
|
|
|
|
class Channel(object):
|
|
"""Class representing a Channel.
|
|
|
|
Converts the csv encoded data into the format that the template (and thus
|
|
the consuming C code) expects.
|
|
|
|
"""
|
|
# If the csv file grew very large this class could be put behind a factory
|
|
# to increase efficiency. Right now though it's fast enough that It didn't
|
|
# seem worthwhile to add all of the boilerplate
|
|
_types = {
|
|
'x': 'void',
|
|
'r': 'raw',
|
|
'un': 'unorm',
|
|
'sn': 'snorm',
|
|
'uf': 'ufloat',
|
|
'sf': 'sfloat',
|
|
'ux': 'ufixed',
|
|
'sx': 'sfixed',
|
|
'ui': 'uint',
|
|
'si': 'sint',
|
|
'us': 'uscaled',
|
|
'ss': 'sscaled',
|
|
}
|
|
_splitter = re.compile(r'\s*(?P<type>[a-z]+)(?P<size>[0-9]+)')
|
|
|
|
def __init__(self, line):
|
|
# If the line is just whitespace then just set everything to None to
|
|
# save on the regex cost and let the template skip on None.
|
|
if line.isspace():
|
|
self.size = None
|
|
self.type = None
|
|
else:
|
|
grouped = self._splitter.match(line)
|
|
self.type = self._types[grouped.group('type')].upper()
|
|
self.size = int(grouped.group('size'))
|
|
|
|
# Default the start bit to -1
|
|
self.start = -1
|
|
|
|
|
|
class Format(object):
|
|
"""Class taht contains all values needed by the template."""
|
|
def __init__(self, line):
|
|
# pylint: disable=invalid-name
|
|
self.name = line[0].strip()
|
|
|
|
# Future division makes this work in python 2.
|
|
self.bpb = int(line[1])
|
|
self.bw = line[2].strip()
|
|
self.bh = line[3].strip()
|
|
self.bd = line[4].strip()
|
|
self.r = Channel(line[5])
|
|
self.g = Channel(line[6])
|
|
self.b = Channel(line[7])
|
|
self.a = Channel(line[8])
|
|
self.l = Channel(line[9])
|
|
self.i = Channel(line[10])
|
|
self.p = Channel(line[11])
|
|
|
|
# Set the start bit value for each channel
|
|
self.order = line[12].strip()
|
|
bit = 0
|
|
for c in self.order:
|
|
chan = getattr(self, c)
|
|
chan.start = bit
|
|
bit = bit + chan.size
|
|
|
|
# Set the uniform channel type, if the format has one.
|
|
#
|
|
# Iterate over all channels, not just those in self.order, because
|
|
# some formats have an empty 'order' field in the CSV (such as
|
|
# YCRCB_NORMAL).
|
|
self.uniform_channel_type = 'VOID'
|
|
for chan in self.channels:
|
|
if chan.type in (None, 'VOID'):
|
|
pass
|
|
elif self.uniform_channel_type == 'VOID':
|
|
self.uniform_channel_type = chan.type
|
|
elif self.uniform_channel_type == chan.type:
|
|
pass
|
|
else:
|
|
self.uniform_channel_type = 'VOID'
|
|
break
|
|
|
|
# alpha doesn't have a colorspace of it's own.
|
|
self.colorspace = line[13].strip().upper()
|
|
if self.colorspace in ['']:
|
|
self.colorspace = 'NONE'
|
|
|
|
# This sets it to the line value, or if it's an empty string 'NONE'
|
|
self.txc = line[14].strip().upper() or 'NONE'
|
|
|
|
|
|
@property
|
|
def channels(self):
|
|
yield self.r
|
|
yield self.g
|
|
yield self.b
|
|
yield self.a
|
|
yield self.l
|
|
yield self.i
|
|
yield self.p
|
|
|
|
|
|
def reader(csvfile):
|
|
"""Wrapper around csv.reader that skips comments and blanks."""
|
|
# csv.reader actually reads the file one line at a time (it was designed to
|
|
# open excel generated sheets), so hold the file until all of the lines are
|
|
# read.
|
|
with open(csvfile, 'r') as f:
|
|
for line in csv.reader(f):
|
|
if line and not line[0].startswith('#'):
|
|
yield line
|
|
|
|
def get_srgb_to_linear_map(formats):
|
|
"""Compute a map from sRGB to linear formats.
|
|
|
|
This function uses some probably somewhat fragile string munging to do
|
|
the conversion. However, we do assert that, if it's SRGB, the munging
|
|
succeeded so that gives some safety.
|
|
"""
|
|
names = {f.name for f in formats}
|
|
for fmt in formats:
|
|
if fmt.colorspace != 'SRGB':
|
|
continue
|
|
|
|
replacements = [
|
|
('_SRGB', ''),
|
|
('SRGB', 'RGB'),
|
|
('U8SRGB', 'FLT16'),
|
|
]
|
|
|
|
found = False
|
|
for rep in replacements:
|
|
rgb_name = fmt.name.replace(rep[0], rep[1])
|
|
if rgb_name in names:
|
|
found = True
|
|
yield fmt.name, rgb_name
|
|
break
|
|
|
|
# We should have found a format name
|
|
assert found
|
|
|
|
def main():
|
|
"""Main function."""
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument('--csv', action='store', help='The CSV file to parse.')
|
|
parser.add_argument(
|
|
'--out',
|
|
action='store',
|
|
help='The location to put the generated C file.')
|
|
args = parser.parse_args()
|
|
|
|
# This generator opens and writes the file itself, and it does so in bytes
|
|
# mode. This solves both python 2 vs 3 problems and solves the locale
|
|
# problem: Unicode can be rendered even if the shell calling this script
|
|
# doesn't.
|
|
with open(args.out, 'wb') as f:
|
|
formats = [Format(l) for l in reader(args.csv)]
|
|
try:
|
|
# This basically does lazy evaluation and initialization, which
|
|
# saves on memory and startup overhead.
|
|
f.write(TEMPLATE.render(
|
|
formats = formats,
|
|
srgb_to_linear_map = list(get_srgb_to_linear_map(formats)),
|
|
))
|
|
except Exception:
|
|
# In the even there's an error this imports some helpers from mako
|
|
# to print a useful stack trace and prints it, then exits with
|
|
# status 1, if python is run with debug; otherwise it just raises
|
|
# the exception
|
|
if __debug__:
|
|
import sys
|
|
from mako import exceptions
|
|
print(exceptions.text_error_template().render(),
|
|
file=sys.stderr)
|
|
sys.exit(1)
|
|
raise
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|