Merge "Don\'t require supported binary formats in negative tests." into marshmallow...
[platform/upstream/VK-GL-CTS.git] / scripts / build_android_mustpass.py
1 # -*- coding: utf-8 -*-
2
3 #-------------------------------------------------------------------------
4 # drawElements Quality Program utilities
5 # --------------------------------------
6 #
7 # Copyright 2015 The Android Open Source Project
8 #
9 # Licensed under the Apache License, Version 2.0 (the "License");
10 # you may not use this file except in compliance with the License.
11 # You may obtain a copy of the License at
12 #
13 #      http://www.apache.org/licenses/LICENSE-2.0
14 #
15 # Unless required by applicable law or agreed to in writing, software
16 # distributed under the License is distributed on an "AS IS" BASIS,
17 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 # See the License for the specific language governing permissions and
19 # limitations under the License.
20 #
21 #-------------------------------------------------------------------------
22
23 from build.common import *
24 from build.config import ANY_GENERATOR
25 from build.build import build
26 from build_caselists import Module, getBuildConfig, genCaseList, getCaseListPath, DEFAULT_BUILD_DIR, DEFAULT_TARGET
27 from fnmatch import fnmatch
28 from copy import copy
29
30 import xml.etree.cElementTree as ElementTree
31 import xml.dom.minidom as minidom
32
33 CTS_DATA_DIR    = os.path.join(DEQP_DIR, "android", "cts")
34
35 class Configuration:
36         def __init__ (self, name, glconfig, rotation, surfacetype, filters):
37                 self.name                       = name
38                 self.glconfig           = glconfig
39                 self.rotation           = rotation
40                 self.surfacetype        = surfacetype
41                 self.filters            = filters
42
43 class Package:
44         def __init__ (self, module, configurations, splitFilters = {}):
45                 self.module                     = module
46                 self.configurations     = configurations
47                 # Map of name:[include filters]. Each will generate <api>.<name> package
48                 # Test cases that didn't match any split filter will be in <api> package,
49                 # i.e., the default value keeps everything in one package.
50                 self.splitFilters   = splitFilters
51
52 class Mustpass:
53         def __init__ (self, version, packages):
54                 self.version    = version
55                 self.packages   = packages
56
57 class Filter:
58         TYPE_INCLUDE = 0
59         TYPE_EXCLUDE = 1
60
61         def __init__ (self, type, filename):
62                 self.type               = type
63                 self.filename   = filename
64
65 class TestRoot:
66         def __init__ (self):
67                 self.children   = []
68
69 class TestGroup:
70         def __init__ (self, name):
71                 self.name               = name
72                 self.children   = []
73
74 class TestCase:
75         def __init__ (self, name):
76                 self.name                       = name
77                 self.configurations     = []
78
79 class GLESVersion:
80         def __init__(self, major, minor):
81                 self.major = major
82                 self.minor = minor
83
84         def encode (self):
85                 return (self.major << 16) | (self.minor)
86
87 def getModuleGLESVersion (module):
88         versions = {
89                 'dEQP-EGL':             GLESVersion(2,0),
90                 'dEQP-GLES2':   GLESVersion(2,0),
91                 'dEQP-GLES3':   GLESVersion(3,0),
92                 'dEQP-GLES31':  GLESVersion(3,1)
93         }
94         return versions[module.name]
95
96 def getSrcDir (mustpass):
97         return os.path.join(CTS_DATA_DIR, mustpass.version, "src")
98
99 def getTmpDir (mustpass):
100         return os.path.join(CTS_DATA_DIR, mustpass.version, "tmp")
101
102 def getModuleShorthand (module):
103         assert module.name[:5] == "dEQP-"
104         return module.name[5:].lower()
105
106 def getCaseListFileName (package, configuration):
107         return "%s-%s.txt" % (getModuleShorthand(package.module), configuration.name)
108
109 def getDstCaseListPath (mustpass, package, configuration):
110         return os.path.join(CTS_DATA_DIR, mustpass.version, getCaseListFileName(package, configuration))
111
112 def getCTSPackageName (package, splitName):
113         if splitName == None:
114                 return "com.drawelements.deqp." + getModuleShorthand(package.module)
115         return "com.drawelements.deqp." + getModuleShorthand(package.module) + "." + splitName
116
117 def getCommandLine (config):
118         return "--deqp-gl-config-name=%s --deqp-screen-rotation=%s --deqp-surface-type=%s --deqp-watchdog=enable" % (config.glconfig, config.rotation, config.surfacetype)
119
120 def readCaseList (filename):
121         cases = []
122         with open(filename, 'rb') as f:
123                 for line in f:
124                         if line[:6] == "TEST: ":
125                                 cases.append(line[6:].strip())
126         return cases
127
128 def getCaseList (mustpass, module):
129         generator       = ANY_GENERATOR
130         buildCfg        = getBuildConfig(DEFAULT_BUILD_DIR, DEFAULT_TARGET, "Debug")
131
132         #build(buildCfg, generator, [module.binName])
133         genCaseList(buildCfg, generator, module, "txt")
134
135         return readCaseList(getCaseListPath(buildCfg, module, "txt"))
136
137 def readPatternList (filename):
138         ptrns = []
139         with open(filename, 'rb') as f:
140                 for line in f:
141                         line = line.strip()
142                         if len(line) > 0 and line[0] != '#':
143                                 ptrns.append(line)
144         return ptrns
145
146 def applyPatterns (caseList, patterns, op):
147         matched                 = set()
148         errors                  = []
149         curList                 = copy(caseList)
150         trivialPtrns    = [p for p in patterns if p.find('*') < 0]
151         regularPtrns    = [p for p in patterns if p.find('*') >= 0]
152
153         # Apply trivial (just case paths)
154         allCasesSet             = set(caseList)
155         for path in trivialPtrns:
156                 if path in allCasesSet:
157                         if path in matched:
158                                 errors.append((path, "Same case specified more than once"))
159                         matched.add(path)
160                 else:
161                         errors.append((path, "Test case not found"))
162
163         curList = [c for c in curList if c not in matched]
164
165         for pattern in regularPtrns:
166                 matchedThisPtrn = set()
167
168                 for case in curList:
169                         if fnmatch(case, pattern):
170                                 matchedThisPtrn.add(case)
171
172                 if len(matchedThisPtrn) == 0:
173                         errors.append((pattern, "Pattern didn't match any cases"))
174
175                 matched = matched | matchedThisPtrn
176                 curList = [c for c in curList if c not in matched]
177
178         for pattern, reason in errors:
179                 print "ERROR: %s: %s" % (reason, pattern)
180
181         if len(errors) > 0:
182                 die("Found %s invalid patterns" % len(errors))
183
184         return [c for c in caseList if op(c in matched)]
185
186 def applyInclude (caseList, patterns):
187         return applyPatterns(caseList, patterns, lambda b: b)
188
189 def applyExclude (caseList, patterns):
190         return applyPatterns(caseList, patterns, lambda b: not b)
191
192 def readPatternLists (mustpass):
193         lists = {}
194         for package in mustpass.packages:
195                 for cfg in package.configurations:
196                         for filter in cfg.filters:
197                                 if not filter.filename in lists:
198                                         lists[filter.filename] = readPatternList(os.path.join(getSrcDir(mustpass), filter.filename))
199         return lists
200
201 def applyFilters (caseList, patternLists, filters):
202         res = copy(caseList)
203         for filter in filters:
204                 ptrnList = patternLists[filter.filename]
205                 if filter.type == Filter.TYPE_INCLUDE:
206                         res = applyInclude(res, ptrnList)
207                 else:
208                         assert filter.type == Filter.TYPE_EXCLUDE
209                         res = applyExclude(res, ptrnList)
210         return res
211
212 def appendToHierarchy (root, casePath):
213         def findChild (node, name):
214                 for child in node.children:
215                         if child.name == name:
216                                 return child
217                 return None
218
219         curNode         = root
220         components      = casePath.split('.')
221
222         for component in components[:-1]:
223                 nextNode = findChild(curNode, component)
224                 if not nextNode:
225                         nextNode = TestGroup(component)
226                         curNode.children.append(nextNode)
227                 curNode = nextNode
228
229         if not findChild(curNode, components[-1]):
230                 curNode.children.append(TestCase(components[-1]))
231
232 def buildTestHierachy (caseList):
233         root = TestRoot()
234         for case in caseList:
235                 appendToHierarchy(root, case)
236         return root
237
238 def buildTestCaseMap (root):
239         caseMap = {}
240
241         def recursiveBuild (curNode, prefix):
242                 curPath = prefix + curNode.name
243                 if isinstance(curNode, TestCase):
244                         caseMap[curPath] = curNode
245                 else:
246                         for child in curNode.children:
247                                 recursiveBuild(child, curPath + '.')
248
249         for child in root.children:
250                 recursiveBuild(child, '')
251
252         return caseMap
253
254 def include (filename):
255         return Filter(Filter.TYPE_INCLUDE, filename)
256
257 def exclude (filename):
258         return Filter(Filter.TYPE_EXCLUDE, filename)
259
260 def prettifyXML (doc):
261         uglyString      = ElementTree.tostring(doc, 'utf-8')
262         reparsed        = minidom.parseString(uglyString)
263         return reparsed.toprettyxml(indent='\t', encoding='utf-8')
264
265 def genCTSPackageXML (package, root, name):
266         def isLeafGroup (testGroup):
267                 numGroups       = 0
268                 numTests        = 0
269
270                 for child in testGroup.children:
271                         if isinstance(child, TestCase):
272                                 numTests += 1
273                         else:
274                                 numGroups += 1
275
276                 assert numGroups + numTests > 0
277
278                 if numGroups > 0 and numTests > 0:
279                         die("Mixed groups and cases in %s" % testGroup.name)
280
281                 return numGroups == 0
282
283         def makeConfiguration (parentElem, configuration):
284                 return ElementTree.SubElement(parentElem, "TestInstance", glconfig=configuration.glconfig, rotation=configuration.rotation, surfacetype=configuration.surfacetype)
285
286         def makeTestCase (parentElem, testCase):
287                 caseElem = ElementTree.SubElement(parentElem, "Test", name=testCase.name)
288                 for config in testCase.configurations:
289                         makeConfiguration(caseElem, config)
290                 return caseElem
291
292         def makeTestGroup (parentElem, testGroup):
293                 groupElem = ElementTree.SubElement(parentElem, "TestCase" if isLeafGroup(testGroup) else "TestSuite", name=testGroup.name)
294                 for child in testGroup.children:
295                         if isinstance(child, TestCase):
296                                 makeTestCase(groupElem, child)
297                         else:
298                                 makeTestGroup(groupElem, child)
299                 return groupElem
300
301         pkgElem = ElementTree.Element("TestPackage",
302                                                                   name                          = package.module.name,
303                                                                   appPackageName        = name,
304                                                                   testType                      = "deqpTest")
305
306         pkgElem.set("xmlns:deqp", "http://drawelements.com/deqp")
307         pkgElem.set("deqp:glesVersion", str(getModuleGLESVersion(package.module).encode()))
308
309         for child in root.children:
310                 makeTestGroup(pkgElem, child)
311
312         return pkgElem
313
314 def genSpecXML (mustpass):
315         mustpassElem = ElementTree.Element("Mustpass", version = mustpass.version)
316
317         for package in mustpass.packages:
318                 packageElem = ElementTree.SubElement(mustpassElem, "TestPackage", name = package.module.name)
319
320                 for config in package.configurations:
321                         configElem = ElementTree.SubElement(packageElem, "Configuration",
322                                                                                                 name                    = config.name,
323                                                                                                 caseListFile    = getCaseListFileName(package, config),
324                                                                                                 commandLine             = getCommandLine(config))
325
326         return mustpassElem
327
328 def genCTSPackage (package, cases, matchingByConfig, packageName, xmlFilename):
329         root            = buildTestHierachy(cases)
330         testCaseMap     = buildTestCaseMap(root)
331
332         for config in package.configurations:
333                 for case in matchingByConfig[config]:
334                         if case in testCaseMap:
335                                 testCaseMap[case].configurations.append(config)
336
337         packageXml      = genCTSPackageXML(package, root, packageName)
338
339         print "  Writing CTS caselist: " + xmlFilename
340         writeFile(xmlFilename, prettifyXML(packageXml))
341
342 def genMustpass (mustpass, moduleCaseLists):
343         print "Generating mustpass '%s'" % mustpass.version
344
345         patternLists = readPatternLists(mustpass)
346
347         for package in mustpass.packages:
348                 allCasesInPkg           = moduleCaseLists[package.module]
349                 matchingByConfig        = {}
350                 allMatchingSet          = set()
351
352                 for config in package.configurations:
353                         filtered        = applyFilters(allCasesInPkg, patternLists, config.filters)
354                         dstFile         = getDstCaseListPath(mustpass, package, config)
355
356                         print "  Writing deqp caselist: " + dstFile
357                         writeFile(dstFile, "\n".join(filtered) + "\n")
358
359                         matchingByConfig[config]        = filtered
360                         allMatchingSet                          = allMatchingSet | set(filtered)
361
362                 allMatchingCases                = [c for c in allCasesInPkg if c in allMatchingSet] # To preserve ordering
363                 splitFilters                    = package.splitFilters
364                 for splitName in splitFilters.keys():
365                         splitIncludeFilters     = splitFilters[splitName]
366                         splitCases                      = applyInclude(allMatchingCases, splitIncludeFilters)
367                         packageName                     = getCTSPackageName(package, splitName)
368                         xmlFilename                     = os.path.join(CTS_DATA_DIR, mustpass.version, packageName + ".xml")
369                         genCTSPackage(package, splitCases, matchingByConfig, packageName, xmlFilename)
370
371                 # The cases not matching any of the includes
372                 combinedSplitFilters    = reduce(lambda x,y: x+y, splitFilters.values(), [])
373                 restOfCases                             = applyExclude(allMatchingCases, combinedSplitFilters)
374                 packageName                             = getCTSPackageName(package, None)
375                 xmlFilename                             = os.path.join(CTS_DATA_DIR, mustpass.version, packageName + ".xml")
376                 genCTSPackage(package, restOfCases, matchingByConfig, packageName, xmlFilename)
377
378         specXML                 = genSpecXML(mustpass)
379         specFilename    = os.path.join(CTS_DATA_DIR, mustpass.version, "mustpass.xml")
380
381         print "  Writing spec: " + specFilename
382         writeFile(specFilename, prettifyXML(specXML))
383
384         print "Done!"
385
386 def genMustpassLists (mustpassLists):
387         moduleCaseLists = {}
388
389         # Getting case lists involves invoking build, so we want to cache the results
390         for mustpass in mustpassLists:
391                 for package in mustpass.packages:
392                         if not package.module in moduleCaseLists:
393                                 moduleCaseLists[package.module] = getCaseList(mustpass, package.module)
394
395         for mustpass in mustpassLists:
396                 genMustpass(mustpass, moduleCaseLists)
397
398 EGL_MODULE                                              = Module(name = "dEQP-EGL", dirName = "egl", binName = "deqp-egl")
399 GLES2_MODULE                                    = Module(name = "dEQP-GLES2", dirName = "gles2", binName = "deqp-gles2")
400 GLES3_MODULE                                    = Module(name = "dEQP-GLES3", dirName = "gles3", binName = "deqp-gles3")
401 GLES31_MODULE                                   = Module(name = "dEQP-GLES31", dirName = "gles31", binName = "deqp-gles31")
402
403 LMP_GLES3_PKG                                   = Package(module = GLES3_MODULE, configurations = [
404                 Configuration(name                      = "master",
405                                           glconfig              = "rgba8888d24s8ms0",
406                                           rotation              = "unspecified",
407                                           surfacetype   = "window",
408                                           filters               = [include("es30-lmp.txt")]),
409         ])
410 LMP_GLES31_PKG                                  = Package(module = GLES31_MODULE, configurations = [
411                 Configuration(name                      = "master",
412                                           glconfig              = "rgba8888d24s8ms0",
413                                           rotation              = "unspecified",
414                                           surfacetype   = "window",
415                                           filters               = [include("es31-lmp.txt")]),
416         ])
417
418 LMP_MR1_GLES3_PKG                               = Package(module = GLES3_MODULE, configurations = [
419                 Configuration(name                      = "master",
420                                           glconfig              = "rgba8888d24s8ms0",
421                                           rotation              = "unspecified",
422                                           surfacetype   = "window",
423                                           filters               = [include("es30-lmp-mr1.txt")]),
424         ])
425 LMP_MR1_GLES31_PKG                              = Package(module = GLES31_MODULE, configurations = [
426                 Configuration(name                      = "master",
427                                           glconfig              = "rgba8888d24s8ms0",
428                                           rotation              = "unspecified",
429                                           surfacetype   = "window",
430                                           filters               = [include("es31-lmp-mr1.txt")]),
431         ])
432
433 MASTER_EGL_COMMON_FILTERS               = [include("egl-master.txt"), exclude("egl-failures.txt")]
434 MASTER_EGL_PKG                                  = Package(module = EGL_MODULE, configurations = [
435                 # Master
436                 Configuration(name                      = "master",
437                                           glconfig              = "rgba8888d24s8ms0",
438                                           rotation              = "unspecified",
439                                           surfacetype   = "window",
440                                           filters               = MASTER_EGL_COMMON_FILTERS),
441         ])
442
443 MASTER_GLES2_COMMON_FILTERS             = [
444                 include("gles2-master.txt"),
445                 exclude("gles2-test-issues.txt"),
446                 exclude("gles2-failures.txt")
447         ]
448 MASTER_GLES2_PKG                                = Package(module = GLES2_MODULE, configurations = [
449                 # Master
450                 Configuration(name                      = "master",
451                                           glconfig              = "rgba8888d24s8ms0",
452                                           rotation              = "unspecified",
453                                           surfacetype   = "window",
454                                           filters               = MASTER_GLES2_COMMON_FILTERS),
455         ])
456
457 MASTER_GLES3_COMMON_FILTERS             = [
458                 include("gles3-master.txt"),
459                 exclude("gles3-hw-issues.txt"),
460                 exclude("gles3-driver-issues.txt"),
461                 exclude("gles3-test-issues.txt"),
462                 exclude("gles3-spec-issues.txt")
463         ]
464 MASTER_GLES3_PKG                                = Package(module = GLES3_MODULE, configurations = [
465                 # Master
466                 Configuration(name                      = "master",
467                                           glconfig              = "rgba8888d24s8ms0",
468                                           rotation              = "unspecified",
469                                           surfacetype   = "window",
470                                           filters               = MASTER_GLES3_COMMON_FILTERS),
471                 # Rotations
472                 Configuration(name                      = "rotate-portrait",
473                                           glconfig              = "rgba8888d24s8ms0",
474                                           rotation              = "0",
475                                           surfacetype   = "window",
476                                           filters               = MASTER_GLES3_COMMON_FILTERS + [include("gles3-rotation.txt")]),
477                 Configuration(name                      = "rotate-landscape",
478                                           glconfig              = "rgba8888d24s8ms0",
479                                           rotation              = "90",
480                                           surfacetype   = "window",
481                                           filters               = MASTER_GLES3_COMMON_FILTERS + [include("gles3-rotation.txt")]),
482                 Configuration(name                      = "rotate-reverse-portrait",
483                                           glconfig              = "rgba8888d24s8ms0",
484                                           rotation              = "180",
485                                           surfacetype   = "window",
486                                           filters               = MASTER_GLES3_COMMON_FILTERS + [include("gles3-rotation.txt")]),
487                 Configuration(name                      = "rotate-reverse-landscape",
488                                           glconfig              = "rgba8888d24s8ms0",
489                                           rotation              = "270",
490                                           surfacetype   = "window",
491                                           filters               = MASTER_GLES3_COMMON_FILTERS + [include("gles3-rotation.txt")]),
492
493                 # MSAA
494                 Configuration(name                      = "multisample",
495                                           glconfig              = "rgba8888d24s8ms4",
496                                           rotation              = "unspecified",
497                                           surfacetype   = "window",
498                                           filters               = MASTER_GLES3_COMMON_FILTERS + [include("gles3-multisample.txt"),
499                                                                                                                                          exclude("gles3-multisample-issues.txt")]),
500
501                 # Pixel format
502                 Configuration(name                      = "565-no-depth-no-stencil",
503                                           glconfig              = "rgb565d0s0ms0",
504                                           rotation              = "unspecified",
505                                           surfacetype   = "window",
506                                           filters               = MASTER_GLES3_COMMON_FILTERS + [include("gles3-pixelformat.txt"),
507                                                                                                                                          exclude("gles3-pixelformat-issues.txt")]),
508         ])
509
510 MASTER_GLES31_COMMON_FILTERS    = [
511                 include("gles31-master.txt"),
512                 exclude("gles31-hw-issues.txt"),
513                 exclude("gles31-driver-issues.txt"),
514                 exclude("gles31-test-issues.txt"),
515                 exclude("gles31-spec-issues.txt"),
516         ]
517 MASTER_GLES31_PKG                               = Package(module = GLES31_MODULE, configurations = [
518                 # Master
519                 Configuration(name                      = "master",
520                                           glconfig              = "rgba8888d24s8ms0",
521                                           rotation              = "unspecified",
522                                           surfacetype   = "window",
523                                           filters               = MASTER_GLES31_COMMON_FILTERS),
524
525                 # Rotations
526                 Configuration(name                      = "rotate-portrait",
527                                           glconfig              = "rgba8888d24s8ms0",
528                                           rotation              = "0",
529                                           surfacetype   = "window",
530                                           filters               = MASTER_GLES31_COMMON_FILTERS + [include("gles31-rotation.txt")]),
531                 Configuration(name                      = "rotate-landscape",
532                                           glconfig              = "rgba8888d24s8ms0",
533                                           rotation              = "90",
534                                           surfacetype   = "window",
535                                           filters               = MASTER_GLES31_COMMON_FILTERS + [include("gles31-rotation.txt")]),
536                 Configuration(name                      = "rotate-reverse-portrait",
537                                           glconfig              = "rgba8888d24s8ms0",
538                                           rotation              = "180",
539                                           surfacetype   = "window",
540                                           filters               = MASTER_GLES31_COMMON_FILTERS + [include("gles31-rotation.txt")]),
541                 Configuration(name                      = "rotate-reverse-landscape",
542                                           glconfig              = "rgba8888d24s8ms0",
543                                           rotation              = "270",
544                                           surfacetype   = "window",
545                                           filters               = MASTER_GLES31_COMMON_FILTERS + [include("gles31-rotation.txt")]),
546
547                 # MSAA
548                 Configuration(name                      = "multisample",
549                                           glconfig              = "rgba8888d24s8ms4",
550                                           rotation              = "unspecified",
551                                           surfacetype   = "window",
552                                           filters               = MASTER_GLES31_COMMON_FILTERS + [include("gles31-multisample.txt")]),
553
554                 # Pixel format
555                 Configuration(name                      = "565-no-depth-no-stencil",
556                                           glconfig              = "rgb565d0s0ms0",
557                                           rotation              = "unspecified",
558                                           surfacetype   = "window",
559                                           filters               = MASTER_GLES31_COMMON_FILTERS + [include("gles31-pixelformat.txt")]),
560         ],
561         splitFilters = {"copy_image_compressed":                        ["dEQP-GLES31.functional.copy_image.compressed.*"],
562                                         "copy_image_non_compressed":            ["dEQP-GLES31.functional.copy_image.non_compressed.*"],
563                                         "copy_image_mixed":                                     ["dEQP-GLES31.functional.copy_image.mixed.*"],
564                                         }
565         )
566
567 MUSTPASS_LISTS                          = [
568                 Mustpass(version = "lmp",               packages = [LMP_GLES3_PKG, LMP_GLES31_PKG]),
569                 Mustpass(version = "lmp-mr1",   packages = [LMP_MR1_GLES3_PKG, LMP_MR1_GLES31_PKG]),
570                 Mustpass(version = "master",    packages = [MASTER_EGL_PKG, MASTER_GLES2_PKG, MASTER_GLES3_PKG, MASTER_GLES31_PKG])
571         ]
572
573 if __name__ == "__main__":
574         genMustpassLists(MUSTPASS_LISTS)