1 # -*- coding: utf-8 -*-
3 #-------------------------------------------------------------------------
4 # drawElements Quality Program utilities
5 # --------------------------------------
7 # Copyright 2015 The Android Open Source Project
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
13 # http://www.apache.org/licenses/LICENSE-2.0
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.
21 #-------------------------------------------------------------------------
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
30 import xml.etree.cElementTree as ElementTree
31 import xml.dom.minidom as minidom
33 CTS_DATA_DIR = os.path.join(DEQP_DIR, "android", "cts")
36 def __init__ (self, name, glconfig, rotation, surfacetype, filters):
38 self.glconfig = glconfig
39 self.rotation = rotation
40 self.surfacetype = surfacetype
41 self.filters = filters
44 def __init__ (self, module, configurations):
46 self.configurations = configurations
49 def __init__ (self, version, packages):
50 self.version = version
51 self.packages = packages
57 def __init__ (self, type, filename):
59 self.filename = filename
66 def __init__ (self, name):
71 def __init__ (self, name):
73 self.configurations = []
76 def __init__(self, major, minor):
81 return (self.major << 16) | (self.minor)
83 def getModuleGLESVersion (module):
85 'dEQP-EGL': GLESVersion(2,0),
86 'dEQP-GLES2': GLESVersion(2,0),
87 'dEQP-GLES3': GLESVersion(3,0),
88 'dEQP-GLES31': GLESVersion(3,1)
90 return versions[module.name]
92 def getSrcDir (mustpass):
93 return os.path.join(CTS_DATA_DIR, mustpass.version, "src")
95 def getTmpDir (mustpass):
96 return os.path.join(CTS_DATA_DIR, mustpass.version, "tmp")
98 def getModuleShorthand (module):
99 assert module.name[:5] == "dEQP-"
100 return module.name[5:].lower()
102 def getCaseListFileName (package, configuration):
103 return "%s-%s.txt" % (getModuleShorthand(package.module), configuration.name)
105 def getDstCaseListPath (mustpass, package, configuration):
106 return os.path.join(CTS_DATA_DIR, mustpass.version, getCaseListFileName(package, configuration))
108 def getCTSPackageName (package):
109 return "com.drawelements.deqp." + getModuleShorthand(package.module)
111 def getCommandLine (config):
112 return "--deqp-gl-config-name=%s --deqp-screen-rotation=%s --deqp-surface-type=%s --deqp-watchdog=enable" % (config.glconfig, config.rotation, config.surfacetype)
114 def readCaseList (filename):
116 with open(filename, 'rb') as f:
118 if line[:6] == "TEST: ":
119 cases.append(line[6:].strip())
122 def getCaseList (mustpass, module):
123 generator = ANY_GENERATOR
124 buildCfg = getBuildConfig(DEFAULT_BUILD_DIR, DEFAULT_TARGET, "Debug")
126 build(buildCfg, generator, [module.binName])
127 genCaseList(buildCfg, generator, module, "txt")
129 return readCaseList(getCaseListPath(buildCfg, module, "txt"))
131 def readPatternList (filename):
133 with open(filename, 'rb') as f:
136 if len(line) > 0 and line[0] != '#':
140 def applyPatterns (caseList, patterns, op):
143 curList = copy(caseList)
144 trivialPtrns = [p for p in patterns if p.find('*') < 0]
145 regularPtrns = [p for p in patterns if p.find('*') >= 0]
147 # Apply trivial (just case paths)
148 allCasesSet = set(caseList)
149 for path in trivialPtrns:
150 if path in allCasesSet:
152 errors.append((path, "Same case specified more than once"))
155 errors.append((path, "Test case not found"))
157 curList = [c for c in curList if c not in matched]
159 for pattern in regularPtrns:
160 matchedThisPtrn = set()
163 if fnmatch(case, pattern):
164 matchedThisPtrn.add(case)
166 if len(matchedThisPtrn) == 0:
167 errors.append((pattern, "Pattern didn't match any cases"))
169 matched = matched | matchedThisPtrn
170 curList = [c for c in curList if c not in matched]
172 for pattern, reason in errors:
173 print "ERROR: %s: %s" % (reason, pattern)
176 die("Found %s invalid patterns" % len(errors))
178 return [c for c in caseList if op(c in matched)]
180 def applyInclude (caseList, patterns):
181 return applyPatterns(caseList, patterns, lambda b: b)
183 def applyExclude (caseList, patterns):
184 return applyPatterns(caseList, patterns, lambda b: not b)
186 def readPatternLists (mustpass):
188 for package in mustpass.packages:
189 for cfg in package.configurations:
190 for filter in cfg.filters:
191 if not filter.filename in lists:
192 lists[filter.filename] = readPatternList(os.path.join(getSrcDir(mustpass), filter.filename))
195 def applyFilters (caseList, patternLists, filters):
197 for filter in filters:
198 ptrnList = patternLists[filter.filename]
199 if filter.type == Filter.TYPE_INCLUDE:
200 res = applyInclude(res, ptrnList)
202 assert filter.type == Filter.TYPE_EXCLUDE
203 res = applyExclude(res, ptrnList)
206 def appendToHierarchy (root, casePath):
207 def findChild (node, name):
208 for child in node.children:
209 if child.name == name:
214 components = casePath.split('.')
216 for component in components[:-1]:
217 nextNode = findChild(curNode, component)
219 nextNode = TestGroup(component)
220 curNode.children.append(nextNode)
223 if not findChild(curNode, components[-1]):
224 curNode.children.append(TestCase(components[-1]))
226 def buildTestHierachy (caseList):
228 for case in caseList:
229 appendToHierarchy(root, case)
232 def buildTestCaseMap (root):
235 def recursiveBuild (curNode, prefix):
236 curPath = prefix + curNode.name
237 if isinstance(curNode, TestCase):
238 caseMap[curPath] = curNode
240 for child in curNode.children:
241 recursiveBuild(child, curPath + '.')
243 for child in root.children:
244 recursiveBuild(child, '')
248 def include (filename):
249 return Filter(Filter.TYPE_INCLUDE, filename)
251 def exclude (filename):
252 return Filter(Filter.TYPE_EXCLUDE, filename)
254 def prettifyXML (doc):
255 uglyString = ElementTree.tostring(doc, 'utf-8')
256 reparsed = minidom.parseString(uglyString)
257 return reparsed.toprettyxml(indent='\t', encoding='utf-8')
259 def genCTSPackageXML (package, root):
260 def isLeafGroup (testGroup):
264 for child in testGroup.children:
265 if isinstance(child, TestCase):
270 assert numGroups + numTests > 0
272 if numGroups > 0 and numTests > 0:
273 die("Mixed groups and cases in %s" % testGroup.name)
275 return numGroups == 0
277 def makeConfiguration (parentElem, configuration):
278 return ElementTree.SubElement(parentElem, "TestInstance", glconfig=configuration.glconfig, rotation=configuration.rotation, surfacetype=configuration.surfacetype)
280 def makeTestCase (parentElem, testCase):
281 caseElem = ElementTree.SubElement(parentElem, "Test", name=testCase.name)
282 for config in testCase.configurations:
283 makeConfiguration(caseElem, config)
286 def makeTestGroup (parentElem, testGroup):
287 groupElem = ElementTree.SubElement(parentElem, "TestCase" if isLeafGroup(testGroup) else "TestSuite", name=testGroup.name)
288 for child in testGroup.children:
289 if isinstance(child, TestCase):
290 makeTestCase(groupElem, child)
292 makeTestGroup(groupElem, child)
295 pkgElem = ElementTree.Element("TestPackage",
296 name = package.module.name,
297 appPackageName = getCTSPackageName(package),
298 testType = "deqpTest")
300 pkgElem.set("xmlns:deqp", "http://drawelements.com/deqp")
301 pkgElem.set("deqp:glesVersion", str(getModuleGLESVersion(package.module).encode()))
303 for child in root.children:
304 makeTestGroup(pkgElem, child)
308 def genSpecXML (mustpass):
309 mustpassElem = ElementTree.Element("Mustpass", version = mustpass.version)
311 for package in mustpass.packages:
312 packageElem = ElementTree.SubElement(mustpassElem, "TestPackage", name = package.module.name)
314 for config in package.configurations:
315 configElem = ElementTree.SubElement(packageElem, "Configuration",
317 caseListFile = getCaseListFileName(package, config),
318 commandLine = getCommandLine(config))
322 def genMustpass (mustpass, moduleCaseLists):
323 print "Generating mustpass '%s'" % mustpass.version
325 patternLists = readPatternLists(mustpass)
327 for package in mustpass.packages:
328 allCasesInPkg = moduleCaseLists[package.module]
329 matchingByConfig = {}
330 allMatchingSet = set()
332 for config in package.configurations:
333 filtered = applyFilters(allCasesInPkg, patternLists, config.filters)
334 dstFile = getDstCaseListPath(mustpass, package, config)
336 print " Writing deqp caselist: " + dstFile
337 writeFile(dstFile, "\n".join(filtered) + "\n")
339 matchingByConfig[config] = filtered
340 allMatchingSet = allMatchingSet | set(filtered)
342 allMatchingCases = [c for c in allCasesInPkg if c in allMatchingSet] # To preserve ordering
343 root = buildTestHierachy(allMatchingCases)
344 testCaseMap = buildTestCaseMap(root)
346 for config in package.configurations:
347 for case in matchingByConfig[config]:
348 testCaseMap[case].configurations.append(config)
350 packageXml = genCTSPackageXML(package, root)
351 xmlFilename = os.path.join(CTS_DATA_DIR, mustpass.version, getCTSPackageName(package) + ".xml")
353 print " Writing CTS caselist: " + xmlFilename
354 writeFile(xmlFilename, prettifyXML(packageXml))
356 specXML = genSpecXML(mustpass)
357 specFilename = os.path.join(CTS_DATA_DIR, mustpass.version, "mustpass.xml")
359 print " Writing spec: " + specFilename
360 writeFile(specFilename, prettifyXML(specXML))
364 def genMustpassLists (mustpassLists):
367 # Getting case lists involves invoking build, so we want to cache the results
368 for mustpass in mustpassLists:
369 for package in mustpass.packages:
370 if not package.module in moduleCaseLists:
371 moduleCaseLists[package.module] = getCaseList(mustpass, package.module)
373 for mustpass in mustpassLists:
374 genMustpass(mustpass, moduleCaseLists)
376 EGL_MODULE = Module(name = "dEQP-EGL", dirName = "egl", binName = "deqp-egl")
377 GLES2_MODULE = Module(name = "dEQP-GLES2", dirName = "gles2", binName = "deqp-gles2")
378 GLES3_MODULE = Module(name = "dEQP-GLES3", dirName = "gles3", binName = "deqp-gles3")
379 GLES31_MODULE = Module(name = "dEQP-GLES31", dirName = "gles31", binName = "deqp-gles31")
381 LMP_GLES3_PKG = Package(module = GLES3_MODULE, configurations = [
382 Configuration(name = "master",
383 glconfig = "rgba8888d24s8ms0",
384 rotation = "unspecified",
385 surfacetype = "window",
386 filters = [include("es30-lmp.txt")]),
388 LMP_GLES31_PKG = Package(module = GLES31_MODULE, configurations = [
389 Configuration(name = "master",
390 glconfig = "rgba8888d24s8ms0",
391 rotation = "unspecified",
392 surfacetype = "window",
393 filters = [include("es31-lmp.txt")]),
396 LMP_MR1_GLES3_PKG = Package(module = GLES3_MODULE, configurations = [
397 Configuration(name = "master",
398 glconfig = "rgba8888d24s8ms0",
399 rotation = "unspecified",
400 surfacetype = "window",
401 filters = [include("es30-lmp-mr1.txt")]),
403 LMP_MR1_GLES31_PKG = Package(module = GLES31_MODULE, configurations = [
404 Configuration(name = "master",
405 glconfig = "rgba8888d24s8ms0",
406 rotation = "unspecified",
407 surfacetype = "window",
408 filters = [include("es31-lmp-mr1.txt")]),
411 MASTER_EGL_COMMON_FILTERS = [include("egl-master.txt"), exclude("egl-failures.txt")]
412 MASTER_EGL_PKG = Package(module = EGL_MODULE, configurations = [
414 Configuration(name = "master",
415 glconfig = "rgba8888d24s8ms0",
416 rotation = "unspecified",
417 surfacetype = "window",
418 filters = MASTER_EGL_COMMON_FILTERS),
421 MASTER_GLES2_COMMON_FILTERS = [include("gles2-master.txt"), exclude("gles2-failures.txt")]
422 MASTER_GLES2_PKG = Package(module = GLES2_MODULE, configurations = [
424 Configuration(name = "master",
425 glconfig = "rgba8888d24s8ms0",
426 rotation = "unspecified",
427 surfacetype = "window",
428 filters = MASTER_GLES2_COMMON_FILTERS),
431 MASTER_GLES3_COMMON_FILTERS = [
432 include("gles3-master.txt"),
433 exclude("gles3-hw-issues.txt"),
434 exclude("gles3-test-issues.txt"),
435 exclude("gles3-spec-issues.txt")
437 MASTER_GLES3_PKG = Package(module = GLES3_MODULE, configurations = [
439 Configuration(name = "master",
440 glconfig = "rgba8888d24s8ms0",
441 rotation = "unspecified",
442 surfacetype = "window",
443 filters = MASTER_GLES3_COMMON_FILTERS),
445 Configuration(name = "rotate-portrait",
446 glconfig = "rgba8888d24s8ms0",
448 surfacetype = "window",
449 filters = MASTER_GLES3_COMMON_FILTERS + [include("gles3-rotation.txt")]),
450 Configuration(name = "rotate-landscape",
451 glconfig = "rgba8888d24s8ms0",
453 surfacetype = "window",
454 filters = MASTER_GLES3_COMMON_FILTERS + [include("gles3-rotation.txt")]),
455 Configuration(name = "rotate-reverse-portrait",
456 glconfig = "rgba8888d24s8ms0",
458 surfacetype = "window",
459 filters = MASTER_GLES3_COMMON_FILTERS + [include("gles3-rotation.txt")]),
460 Configuration(name = "rotate-reverse-landscape",
461 glconfig = "rgba8888d24s8ms0",
463 surfacetype = "window",
464 filters = MASTER_GLES3_COMMON_FILTERS + [include("gles3-rotation.txt")]),
467 Configuration(name = "multisample",
468 glconfig = "rgba8888d24s8ms4",
469 rotation = "unspecified",
470 surfacetype = "window",
471 filters = MASTER_GLES3_COMMON_FILTERS + [include("gles3-multisample.txt")]),
474 Configuration(name = "565-no-depth-no-stencil",
475 glconfig = "rgb565d0s0ms0",
476 rotation = "unspecified",
477 surfacetype = "window",
478 filters = MASTER_GLES3_COMMON_FILTERS + [include("gles3-pixelformat.txt")]),
481 MASTER_GLES31_COMMON_FILTERS = [
482 include("gles31-master.txt"),
483 exclude("gles31-hw-issues.txt"),
484 exclude("gles31-test-issues.txt"),
486 MASTER_GLES31_PKG = Package(module = GLES31_MODULE, configurations = [
488 Configuration(name = "master",
489 glconfig = "rgba8888d24s8ms0",
490 rotation = "unspecified",
491 surfacetype = "window",
492 filters = MASTER_GLES31_COMMON_FILTERS),
495 Configuration(name = "rotate-portrait",
496 glconfig = "rgba8888d24s8ms0",
498 surfacetype = "window",
499 filters = MASTER_GLES31_COMMON_FILTERS + [include("gles31-rotation.txt")]),
500 Configuration(name = "rotate-landscape",
501 glconfig = "rgba8888d24s8ms0",
503 surfacetype = "window",
504 filters = MASTER_GLES31_COMMON_FILTERS + [include("gles31-rotation.txt")]),
505 Configuration(name = "rotate-reverse-portrait",
506 glconfig = "rgba8888d24s8ms0",
508 surfacetype = "window",
509 filters = MASTER_GLES31_COMMON_FILTERS + [include("gles31-rotation.txt")]),
510 Configuration(name = "rotate-reverse-landscape",
511 glconfig = "rgba8888d24s8ms0",
513 surfacetype = "window",
514 filters = MASTER_GLES31_COMMON_FILTERS + [include("gles31-rotation.txt")]),
517 Configuration(name = "multisample",
518 glconfig = "rgba8888d24s8ms4",
519 rotation = "unspecified",
520 surfacetype = "window",
521 filters = MASTER_GLES31_COMMON_FILTERS + [include("gles31-multisample.txt")]),
524 Configuration(name = "565-no-depth-no-stencil",
525 glconfig = "rgb565d0s0ms0",
526 rotation = "unspecified",
527 surfacetype = "window",
528 filters = MASTER_GLES31_COMMON_FILTERS + [include("gles31-pixelformat.txt")]),
532 Mustpass(version = "lmp", packages = [LMP_GLES3_PKG, LMP_GLES31_PKG]),
533 Mustpass(version = "lmp-mr1", packages = [LMP_MR1_GLES3_PKG, LMP_MR1_GLES31_PKG]),
534 Mustpass(version = "master", packages = [MASTER_EGL_PKG, MASTER_GLES2_PKG, MASTER_GLES3_PKG, MASTER_GLES31_PKG])
537 if __name__ == "__main__":
538 genMustpassLists(MUSTPASS_LISTS)