1# coding=utf-8 2# Copyright (c) 2015-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"""Generate tests for variable index writes. 23 24This creates a TestParams object for each invocation (using a factory to reduce 25the number of duplicate objects), and then passes that into a mako template. 26The template then formats that information into a shader_test for either the 27fragment shader stage or the vertex shader stage. 28 29""" 30import copy 31import itertools 32import os 33 34from modules import utils, glsl 35from templates import template_dir 36 37_TEMPLATES = template_dir(os.path.basename(os.path.splitext(__file__)[0])) 38_VS_TEMPLATE = _TEMPLATES.get_template('vs.shader_test.mako') 39_FS_TEMPLATE = _TEMPLATES.get_template('fs.shader_test.mako') 40_DIRNAME = os.path.join('spec', 'glsl-{}', 'execution', 'variable-indexing') 41 42 43class TestParams(object): 44 """Object representing all of the parameters of a single test instance. 45 46 Provides all of the values using lazy properties, which tie in with the 47 ParamsFactory to store all of the values, speeding up run times. 48 49 """ 50 def __init__(self, mode, array_dim, matrix_dim, index_value, col, 51 value_type, glsl_version): 52 # pylint: disable=too-many-arguments 53 assert array_dim in [0, 3] 54 assert matrix_dim in [2, 3, 4] 55 56 self.mode = mode 57 self.array_dim = array_dim 58 self.matrix_dim = matrix_dim 59 self.index_value = index_value 60 self.col = '[{}]'.format(col) 61 self.value_type = value_type 62 self.version = glsl.Version(glsl_version) 63 64 @utils.lazy_property 65 def varying_comps(self): 66 if self.array_dim != 0: 67 return self.matrix_dim**2 * self.array_dim 68 else: 69 return self.matrix_dim**2 70 71 @utils.lazy_property 72 def base_type(self): 73 if int(self.version) >= 120: 74 return 'mat{0}x{0}'.format(self.matrix_dim) 75 else: 76 return 'mat{}'.format(self.matrix_dim) 77 78 @utils.lazy_property 79 def type(self): 80 if self.array_dim != 0 and int(self.version) >= 120: 81 return '{}[{}]'.format(self.base_type, self.array_dim) 82 else: 83 return self.base_type 84 85 @utils.lazy_property 86 def dim(self): 87 if self.array_dim != 0 and int(self.version) < 120: 88 return '[{}]'.format(self.array_dim) 89 else: 90 return '' 91 92 @utils.lazy_property 93 def row(self): 94 if self.value_type == 'float': 95 return '[row]' 96 else: 97 return '' 98 99 @utils.lazy_property 100 def idx(self): 101 if self.array_dim != 0: 102 return '[{}]'.format(self.index_value) 103 else: 104 return '' 105 106 @utils.lazy_property 107 def idx2(self): 108 if self.array_dim != 0: 109 if self.index_value == 'index': 110 return '[{}2]'.format(self.index_value) 111 else: 112 return '[{}]'.format(self.index_value) 113 else: 114 return '' 115 116 @utils.lazy_property 117 def test_vec(self): 118 if self.matrix_dim == 2: 119 return ["0.803161418975390", "0.852987140792140"] 120 elif self.matrix_dim == 3: 121 return ["0.681652305322399", "0.210426138878113", 122 "0.185916924650237"] 123 elif self.matrix_dim == 4: 124 return ["0.0394868046587045", "0.8922408276905568", 125 "0.3337495624366961", "0.8732295730825839"] 126 127 @utils.lazy_property 128 def test_exp(self): 129 if self.matrix_dim == 2: 130 return ["0.708718134966688", "1.452243795483797"] 131 elif self.matrix_dim == 3: 132 return ["0.610649606928364", "0.711906885823636", 133 "0.312244778977868"] 134 elif self.matrix_dim == 4: 135 return ["1.03935908892461", "1.18846180713529", "1.10078681232072", 136 "1.72434439561820"] 137 138 @utils.lazy_property 139 def test_mat(self): 140 if self.matrix_dim == 2: 141 return [["0.241498998195656", "0.861223395812970"], 142 ["0.603473877011433", "0.891622340451180"]] 143 elif self.matrix_dim == 3: 144 return [ 145 ["0.493944462129466", "0.722190133917966", "0.239853948232558"], 146 ["0.550143078409278", "0.591962645398579", "0.467616286531193"], 147 ["0.850846377186973", "0.511303112962423", "0.270815003356504"] 148 ] 149 elif self.matrix_dim == 4: 150 return [["0.922040144261674", "0.158053783109488", 151 "0.357016429866574", "0.836368810383957"], 152 ["0.560251913703792", "0.171634921595771", 153 "0.602494709909111", "0.693273570571311"], 154 ["0.350720358904176", "0.912192627475775", 155 "0.688544081259531", "0.913891056231967"], 156 ["0.442058176039301", "0.829835836794679", 157 "0.365674411003021", "0.879197364462782"]] 158 159 @utils.lazy_property 160 def test_sizes(self): 161 if self.array_dim == 0: 162 return [1] 163 elif self.index_value == 'index': 164 return list(range(1, self.array_dim + 1)) 165 else: 166 return [2] 167 168 @utils.lazy_property 169 def test_columns(self): 170 if self.col == '[col]': 171 return list(range(1, self.matrix_dim + 1)) 172 return [2] 173 174 @utils.lazy_property 175 def test_rows(self): 176 if self.value_type == 'float': 177 return list(range(1, self.matrix_dim + 1)) 178 return [1] 179 180 @utils.lazy_property 181 def test_type(self): 182 # shader_runner always uses matDxD format 183 return 'mat{0}x{0}'.format(self.matrix_dim) 184 185 def test_matrix(self, column, row): 186 """Generate the matrix used in a test section. 187 188 This will take the matrix used by the test, and replace specific values 189 with sentinal values, and return the matrix as a string. 190 191 """ 192 bad = ['666.0', '777.0', '888.0', '999.0'] 193 mat = copy.deepcopy(self.test_mat) 194 195 if self.value_type == 'float': 196 mat[column][row] = bad[0] 197 else: 198 mat[column] = bad[0:self.matrix_dim] 199 200 ret = '' 201 for c in mat: 202 ret += ' '.join(c) 203 ret += ' ' 204 return ret 205 206 @utils.lazy_property 207 def formated_version(self): 208 # Note: GLSLVersion.float() does division by 100 209 return '{:.2f}'.format(float(self.version)) 210 211 212class ParamsFactory(object): # pylint: disable=too-few-public-methods 213 """A factory class that provides TestParam objects. 214 215 This cuts the number of new objects created by roughly 3/5. 216 217 """ 218 def __init__(self): 219 self.__stored = {} 220 221 def get(self, *args): 222 args = tuple(args) 223 try: 224 return self.__stored[args] 225 except KeyError: 226 params = TestParams(*args) 227 self.__stored[args] = params 228 return params 229 230 231def make_vs(name, params): 232 """Create a vertex shader test.""" 233 dirname = _DIRNAME.format(params.formated_version) 234 utils.safe_makedirs(dirname) 235 with open(os.path.join(dirname, name), 'w') as f: 236 f.write(_VS_TEMPLATE.render_unicode(params=params)) 237 print(name) 238 239 240def make_fs(name, params): 241 """Create a fragment shader test.""" 242 dirname = _DIRNAME.format(params.formated_version) 243 utils.safe_makedirs(dirname) 244 with open(os.path.join(dirname, name), 'w') as f: 245 f.write(_FS_TEMPLATE.render_unicode(params=params)) 246 print(name) 247 248 249def main(): 250 """The main function.""" 251 # Various choices that can be put together to produce a single test. 252 iter_ = itertools.product( 253 ['110', '120'], # GLSL versions 254 [0, 3], # Array dimensions 255 [2, 3, 4], # Matrix dimensions 256 ['varying', 'temp'], # modes 257 ['col', 1], # columns 258 ['fs', 'vs'], # shader stages 259 ) 260 261 factory = ParamsFactory() 262 263 # This can be filled in to produce the file name for the test. 264 # Note that idx, col, row, and arr will need to have a '-' added to the end 265 # of the value if it is not empty 266 name = '{stage}-{mode}-{arr}mat{matrix_dim}-{idx}{col}{row}wr.shader_test' 267 268 for v, a, d, m, c, s in iter_: 269 for t in ['float', 'vec{}'.format(d)]: 270 if s == 'vs': 271 func = make_vs 272 elif s == 'fs': 273 if m == 'varying': 274 # Fragment shaders cannot write varyings 275 continue 276 func = make_fs 277 278 if a != 0: 279 arr = 'array-' 280 281 func( 282 name.format(stage=s, 283 mode=m, 284 matrix_dim=d, 285 arr=arr, 286 idx='', 287 col='col-' if c == 'col' else '', 288 row='row-' if t == 'float' else ''), 289 factory.get(m, a, d, 1, c, t, v)) 290 else: 291 arr = '' 292 293 func( 294 name.format(stage=s, 295 mode=m, 296 matrix_dim=d, 297 arr=arr, 298 idx='index-' if a != 0 else '', 299 col='col-' if c == 'col' else '', 300 row='row-' if t == 'float' else ''), 301 factory.get(m, a, d, 'index', c, t, v)) 302 303 304if __name__ == '__main__': 305 main() 306