| Index: conformance/ogles/process-ogles2-tests.py
|
| ===================================================================
|
| --- conformance/ogles/process-ogles2-tests.py (revision 0)
|
| +++ conformance/ogles/process-ogles2-tests.py (working copy)
|
| @@ -0,0 +1,587 @@
|
| +#!/usr/bin/python
|
| +
|
| +"""generates tests from OpenGL ES 2.0 .run/.test files."""
|
| +
|
| +import os
|
| +import os.path
|
| +import sys
|
| +import re
|
| +import json
|
| +import shutil
|
| +from optparse import OptionParser
|
| +from xml.dom.minidom import parse
|
| +
|
| +if sys.version < '2.6':
|
| + print 'Wrong Python Version !!!: Need >= 2.6'
|
| + sys.exit(1)
|
| +
|
| +# each shader test generates up to 3 512x512 images.
|
| +# a 512x512 image takes 1meg of memory so set this
|
| +# number apporpriate for the platform with
|
| +# the smallest memory issue. At 8 that means
|
| +# at least 24 meg is needed to run the test.
|
| +MAX_TESTS_PER_SET = 8
|
| +
|
| +VERBOSE = False
|
| +
|
| +FILTERS = [
|
| + re.compile("GL/"),
|
| +]
|
| +
|
| +LICENSE = """
|
| +/*
|
| +** Copyright (c) 2012 The Khronos Group Inc.
|
| +**
|
| +** Permission is hereby granted, free of charge, to any person obtaining a
|
| +** copy of this software and/or associated documentation files (the
|
| +** "Materials"), to deal in the Materials without restriction, including
|
| +** without limitation the rights to use, copy, modify, merge, publish,
|
| +** distribute, sublicense, and/or sell copies of the Materials, and to
|
| +** permit persons to whom the Materials are 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 Materials.
|
| +**
|
| +** THE MATERIALS ARE 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
|
| +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
| +*/
|
| +"""
|
| +
|
| +COMMENT_RE = re.compile("/\*\n\*\*\s+Copyright.*?\*/",
|
| + re.IGNORECASE | re.DOTALL)
|
| +REMOVE_COPYRIGHT_RE = re.compile("\/\/\s+Copyright.*?\n",
|
| + re.IGNORECASE | re.DOTALL)
|
| +MATRIX_RE = re.compile("Matrix(\\d)")
|
| +
|
| +VALID_UNIFORM_TYPES = [
|
| + "uniform1f",
|
| + "uniform1fv",
|
| + "uniform1fv",
|
| + "uniform1i",
|
| + "uniform1iv",
|
| + "uniform1iv",
|
| + "uniform2f",
|
| + "uniform2fv",
|
| + "uniform2fv",
|
| + "uniform2i",
|
| + "uniform2iv",
|
| + "uniform2iv",
|
| + "uniform3f",
|
| + "uniform3fv",
|
| + "uniform3fv",
|
| + "uniform3i",
|
| + "uniform3iv",
|
| + "uniform3iv",
|
| + "uniform4f",
|
| + "uniform4fv",
|
| + "uniform4fv",
|
| + "uniform4i",
|
| + "uniform4iv",
|
| + "uniform4ivy",
|
| + "uniformMatrix2fv",
|
| + "uniformMatrix2fv",
|
| + "uniformMatrix3fv",
|
| + "uniformMatrix3fv",
|
| + "uniformMatrix4fv",
|
| + "uniformMatrix4fv",
|
| +]
|
| +
|
| +SUBSTITUTIONS = [
|
| + ("uniformmat3fv", "uniformMatrix3fv"),
|
| + ("uniformmat4fv", "uniformMatrix4fv"),
|
| +]
|
| +
|
| +
|
| +def Log(msg):
|
| + global VERBOSE
|
| + if VERBOSE:
|
| + print msg
|
| +
|
| +
|
| +def TransposeMatrix(values, dim):
|
| + size = dim * dim
|
| + count = len(values) / size
|
| + for m in range(0, count):
|
| + offset = m * size
|
| + for i in range(0, dim):
|
| + for j in range(i + 1, dim):
|
| + t = values[offset + i * dim + j]
|
| + values[offset + i * dim + j] = values[offset + j * dim + i]
|
| + values[offset + j * dim + i] = t
|
| +
|
| +
|
| +def GetValidTypeName(type_name):
|
| + global VALID_UNIFORM_TYPES
|
| + global SUBSTITUTIONS
|
| + for subst in SUBSTITUTIONS:
|
| + type_name = type_name.replace(subst[0], subst[1])
|
| + if not type_name in VALID_UNIFORM_TYPES:
|
| + print "unknown type name: ", type_name
|
| + raise SyntaxError
|
| + return type_name
|
| +
|
| +
|
| +def WriteOpen(filename):
|
| + dirname = os.path.dirname(filename)
|
| + if len(dirname) > 0 and not os.path.exists(dirname):
|
| + os.makedirs(dirname)
|
| + return open(filename, "wb")
|
| +
|
| +
|
| +class TxtWriter():
|
| + def __init__(self, filename):
|
| + self.filename = filename
|
| + self.lines = []
|
| +
|
| + def Write(self, line):
|
| + self.lines.append(line)
|
| +
|
| + def Close(self):
|
| + if len(self.lines) > 0:
|
| + Log("Writing: %s" % self.filename)
|
| + f = WriteOpen(self.filename)
|
| + f.write("# this file is auto-generated. DO NOT EDIT.\n")
|
| + f.write("".join(self.lines))
|
| + f.close()
|
| +
|
| +
|
| +def ReadFileAsLines(filename):
|
| + f = open(filename, "r")
|
| + lines = f.readlines()
|
| + f.close()
|
| + return [line.strip() for line in lines]
|
| +
|
| +
|
| +def ReadFile(filename):
|
| + f = open(filename, "r")
|
| + content = f.read()
|
| + f.close()
|
| + return content.replace("\r\n", "\n")
|
| +
|
| +
|
| +def Chunkify(list, chunk_size):
|
| + """divides an array into chunks of chunk_size"""
|
| + return [list[i:i + chunk_size] for i in range(0, len(list), chunk_size)]
|
| +
|
| +
|
| +def GetText(nodelist):
|
| + """Gets the text of from a list of nodes"""
|
| + rc = []
|
| + for node in nodelist:
|
| + if node.nodeType == node.TEXT_NODE:
|
| + rc.append(node.data)
|
| + return ''.join(rc)
|
| +
|
| +
|
| +def GetElementText(node, name):
|
| + """Gets the text of an element"""
|
| + elements = node.getElementsByTagName(name)
|
| + if len(elements) > 0:
|
| + return GetText(elements[0].childNodes)
|
| + else:
|
| + return None
|
| +
|
| +
|
| +def GetBoolElement(node, name):
|
| + text = GetElementText(node, name)
|
| + return text.lower() == "true"
|
| +
|
| +
|
| +def GetModel(node):
|
| + """Gets the model"""
|
| + model = GetElementText(node, "model")
|
| + if model and len(model.strip()) == 0:
|
| + elements = node.getElementsByTagName("model")
|
| + if len(elements) > 0:
|
| + model = GetElementText(elements[0], "filename")
|
| + return model
|
| +
|
| +
|
| +def RelativizePaths(base, paths, template):
|
| + """converts paths to relative paths"""
|
| + rels = []
|
| + for p in paths:
|
| + #print "---"
|
| + #print "base: ", os.path.abspath(base)
|
| + #print "path: ", os.path.abspath(p)
|
| + relpath = os.path.relpath(os.path.abspath(p), os.path.dirname(os.path.abspath(base))).replace("\\", "/")
|
| + #print "rel : ", relpath
|
| + rels.append(template % relpath)
|
| + return "\n".join(rels)
|
| +
|
| +
|
| +def CopyFile(filename, src, dst):
|
| + s = os.path.abspath(os.path.join(os.path.dirname(src), filename))
|
| + d = os.path.abspath(os.path.join(os.path.dirname(dst), filename))
|
| + dst_dir = os.path.dirname(d)
|
| + if not os.path.exists(dst_dir):
|
| + os.makedirs(dst_dir)
|
| + shutil.copyfile(s, d)
|
| +
|
| +
|
| +def CopyShader(filename, src, dst):
|
| + s = os.path.abspath(os.path.join(os.path.dirname(src), filename))
|
| + d = os.path.abspath(os.path.join(os.path.dirname(dst), filename))
|
| + text = ReadFile(s)
|
| + # By agreement with the Khronos OpenGL working group we are allowed
|
| + # to open source only the .vert and .frag files from the OpenGL ES 2.0
|
| + # conformance tests. All other files from the OpenGL ES 2.0 conformance
|
| + # tests are not included.
|
| + marker = "insert-copyright-here"
|
| + new_text = COMMENT_RE.sub(marker, text)
|
| + if new_text == text:
|
| + print "no matching license found:", s
|
| + raise RuntimeError
|
| + new_text = REMOVE_COPYRIGHT_RE.sub("", new_text)
|
| + new_text = new_text.replace(marker, LICENSE)
|
| + f = WriteOpen(d)
|
| + f.write(new_text)
|
| + f.close()
|
| +
|
| +
|
| +def IsOneOf(string, regexs):
|
| + for regex in regexs:
|
| + if re.match(regex, string):
|
| + return True
|
| + return False
|
| +
|
| +
|
| +def CheckForUnknownTags(valid_tags, node, depth=1):
|
| + """do a hacky check to make sure we're not missing something."""
|
| + for child in node.childNodes:
|
| + if child.localName and not IsOneOf(child.localName, valid_tags[0]):
|
| + print "unsupported tag:", child.localName
|
| + print "depth:", depth
|
| + raise SyntaxError
|
| + else:
|
| + if len(valid_tags) > 1:
|
| + CheckForUnknownTags(valid_tags[1:], child, depth + 1)
|
| +
|
| +
|
| +def IsFileWeWant(filename):
|
| + for f in FILTERS:
|
| + if f.search(filename):
|
| + return True
|
| + return False
|
| +
|
| +
|
| +class TestReader():
|
| + """class to read and parse tests"""
|
| +
|
| + def __init__(self, basepath):
|
| + self.tests = []
|
| + self.modes = {}
|
| + self.patterns = {}
|
| + self.basepath = basepath
|
| +
|
| + def Print(self, msg):
|
| + if self.verbose:
|
| + print msg
|
| +
|
| + def MakeOutPath(self, filename):
|
| + relpath = os.path.relpath(os.path.abspath(filename), os.path.dirname(os.path.abspath(self.basepath)))
|
| + return relpath
|
| +
|
| + def ReadTests(self, filename):
|
| + """reads a .run file and parses."""
|
| + Log("reading %s" % filename)
|
| + outname = self.MakeOutPath(filename + ".txt")
|
| + f = TxtWriter(outname)
|
| + dirname = os.path.dirname(filename)
|
| + lines = ReadFileAsLines(filename)
|
| + count = 0
|
| + tests_data = []
|
| + for line in lines:
|
| + if len(line) > 0 and not line.startswith("#"):
|
| + fname = os.path.join(dirname, line)
|
| + if line.endswith(".run"):
|
| + if self.ReadTests(fname):
|
| + f.Write(line + ".txt\n")
|
| + count += 1
|
| + elif line.endswith(".test"):
|
| + tests_data.extend(self.ReadTest(fname))
|
| + else:
|
| + print "Error in %s:%d:%s" % (filename, count, line)
|
| + raise SyntaxError()
|
| + if len(tests_data):
|
| + global MAX_TESTS_PER_SET
|
| + sets = Chunkify(tests_data, MAX_TESTS_PER_SET)
|
| + id = 1
|
| + for set in sets:
|
| + suffix = "_%03d_to_%03d" % (id, id + len(set) - 1)
|
| + test_outname = self.MakeOutPath(filename + suffix + ".html")
|
| + if os.path.basename(test_outname).startswith("input.run"):
|
| + dname = os.path.dirname(test_outname)
|
| + folder_name = os.path.basename(dname)
|
| + test_outname = os.path.join(dname, folder_name + suffix + ".html")
|
| + self.WriteTests(filename, test_outname, {"tests":set})
|
| + f.Write(os.path.basename(test_outname) + "\n")
|
| + id += len(set)
|
| + count += 1
|
| + f.Close()
|
| + return count
|
| +
|
| + def ReadTest(self, filename):
|
| + """reads a .test file and parses."""
|
| + Log("reading %s" % filename)
|
| + dom = parse(filename)
|
| + tests = dom.getElementsByTagName("test")
|
| + tests_data = []
|
| + outname = self.MakeOutPath(filename + ".html")
|
| + for test in tests:
|
| + if not IsFileWeWant(filename):
|
| + self.CopyShaders(test, filename, outname)
|
| + else:
|
| + test_data = self.ProcessTest(test, filename, outname, len(tests_data))
|
| + if test_data:
|
| + tests_data.append(test_data)
|
| + return tests_data
|
| +
|
| + def ProcessTest(self, test, filename, outname, id):
|
| + """Process a test"""
|
| + mode = test.getAttribute("mode")
|
| + pattern = test.getAttribute("pattern")
|
| + self.modes[mode] = 1
|
| + self.patterns[pattern] = 1
|
| + Log ("%d: mode: %s pattern: %s" % (id, mode, pattern))
|
| + method = getattr(self, 'Process_' + pattern)
|
| + test_data = method(test, filename, outname)
|
| + if test_data:
|
| + test_data["pattern"] = pattern
|
| + return test_data
|
| +
|
| + def WriteTests(self, filename, outname, tests_data):
|
| + Log("Writing %s" % outname)
|
| + template = """<!DOCTYPE html>
|
| +<!-- this file is auto-generated. DO NOT EDIT.
|
| +%(license)s
|
| +-->
|
| +<html>
|
| +<head>
|
| +<meta charset="utf-8">
|
| +<title>WebGL GLSL conformance test: %(title)s</title>
|
| +%(css)s
|
| +%(scripts)s
|
| +</head>
|
| +<body>
|
| +<canvas id="example" width="500" height="500" style="width: 16px; height: 16px;"></canvas>
|
| +<div id="description"></div>
|
| +<div id="console"></div>
|
| +</body>
|
| +<script>
|
| +"use strict";
|
| +OpenGLESTestRunner.run(%(tests_data)s);
|
| +var successfullyParsed = true;
|
| +</script>
|
| +</html>
|
| +"""
|
| + css = [
|
| + "../../resources/js-test-style.css",
|
| + "../resources/ogles-tests.css",
|
| + ]
|
| + scripts = [
|
| + "../../resources/js-test-pre.js",
|
| + "../resources/webgl-test.js",
|
| + "../resources/webgl-test-utils.js",
|
| + "ogles-utils.js",
|
| + ]
|
| + css_html = RelativizePaths(outname, css, '<link rel="stylesheet" href="%s" />')
|
| + scripts_html = RelativizePaths(outname, scripts, '<script src="%s"></script>')
|
| +
|
| + f = WriteOpen(outname)
|
| + f.write(template % {
|
| + "license": LICENSE,
|
| + "css": css_html,
|
| + "scripts": scripts_html,
|
| + "title": os.path.basename(outname),
|
| + "tests_data": json.dumps(tests_data, indent=2)
|
| + })
|
| + f.close()
|
| +
|
| +
|
| + def CopyShaders(self, test, filename, outname):
|
| + """For tests we don't actually support yet, at least copy the shaders"""
|
| + shaders = test.getElementsByTagName("shader")
|
| + for shader in shaders:
|
| + for name in ["vertshader", "fragshader"]:
|
| + s = GetElementText(shader, name)
|
| + if s and s != "empty":
|
| + CopyShader(s, filename, outname)
|
| +
|
| + #
|
| + # pattern handlers.
|
| + #
|
| +
|
| + def Process_compare(self, test, filename, outname):
|
| + global MATRIX_RE
|
| +
|
| + valid_tags = [
|
| + ["shader", "model", "glstate"],
|
| + ["uniform", "vertshader", "fragshader", "filename", "depthrange"],
|
| + ["name", "count", "transpose", "uniform*", "near", "far"],
|
| + ]
|
| + CheckForUnknownTags(valid_tags, test)
|
| +
|
| + # parse the test
|
| + shaders = test.getElementsByTagName("shader")
|
| + shaderInfos = []
|
| + for shader in shaders:
|
| + v = GetElementText(shader, "vertshader")
|
| + f = GetElementText(shader, "fragshader")
|
| + CopyShader(v, filename, outname)
|
| + CopyShader(f, filename, outname)
|
| + info = {
|
| + "vertexShader": v,
|
| + "fragmentShader": f,
|
| + }
|
| + shaderInfos.append(info)
|
| + uniformElems = shader.getElementsByTagName("uniform")
|
| + if len(uniformElems) > 0:
|
| + uniforms = {}
|
| + info["uniforms"] = uniforms
|
| + for uniformElem in uniformElems:
|
| + uniform = {"count": 1}
|
| + for child in uniformElem.childNodes:
|
| + if child.localName == None:
|
| + pass
|
| + elif child.localName == "name":
|
| + uniforms[GetText(child.childNodes)] = uniform
|
| + elif child.localName == "count":
|
| + uniform["count"] = int(GetText(child.childNodes))
|
| + elif child.localName == "transpose":
|
| + uniform["transpose"] = (GetText(child.childNodes) == "true")
|
| + else:
|
| + if "type" in uniform:
|
| + print "utype was:", uniform["type"], " found ", child.localName
|
| + raise SyntaxError
|
| + type_name = GetValidTypeName(child.localName)
|
| + uniform["type"] = type_name
|
| + valueText = GetText(child.childNodes).replace(",", " ")
|
| + uniform["value"] = [float(t) for t in valueText.split()]
|
| + m = MATRIX_RE.search(type_name)
|
| + if m:
|
| + # Why are these backward from the API?!?!?
|
| + TransposeMatrix(uniform["value"], int(m.group(1)))
|
| + data = {
|
| + "name": os.path.basename(outname),
|
| + "model": GetModel(test),
|
| + "referenceProgram": shaderInfos[1],
|
| + "testProgram": shaderInfos[0],
|
| + }
|
| + gl_states = test.getElementsByTagName("glstate")
|
| + if len(gl_states) > 0:
|
| + state = {}
|
| + data["state"] = state
|
| + for gl_state in gl_states:
|
| + for state_name in gl_state.childNodes:
|
| + if state_name.localName:
|
| + values = {}
|
| + for field in state_name.childNodes:
|
| + if field.localName:
|
| + values[field.localName] = GetText(field.childNodes)
|
| + state[state_name.localName] = values
|
| + return data
|
| +
|
| + def Process_shaderload(self, test, filename, outname):
|
| + """no need for shaderload tests"""
|
| + self.CopyShaders(test, filename, outname)
|
| +
|
| + def Process_extension(self, test, filename, outname):
|
| + """no need for extension tests"""
|
| + self.CopyShaders(test, filename, outname)
|
| +
|
| + def Process_createtests(self, test, filename, outname):
|
| + Log("createtests Not implemented: %s" % filename)
|
| + self.CopyShaders(test, filename, outname)
|
| +
|
| + def Process_GL2Test(self, test, filename, outname):
|
| + Log("GL2Test Not implemented: %s" % filename)
|
| + self.CopyShaders(test, filename, outname)
|
| +
|
| + def Process_uniformquery(self, test, filename, outname):
|
| + Log("uniformquery Not implemented: %s" % filename)
|
| + self.CopyShaders(test, filename, outname)
|
| +
|
| + def Process_egl_image_external(self, test, filename, outname):
|
| + """no need for egl_image_external tests"""
|
| + self.CopyShaders(test, filename, outname)
|
| +
|
| + def Process_dismount(self, test, filename, outname):
|
| + Log("dismount Not implemented: %s" % filename)
|
| + self.CopyShaders(test, filename, outname)
|
| +
|
| + def Process_build(self, test, filename, outname):
|
| + """don't need build tests"""
|
| + valid_tags = [
|
| + ["shader", "compstat", "linkstat"],
|
| + ["vertshader", "fragshader"],
|
| + ]
|
| + CheckForUnknownTags(valid_tags, test)
|
| +
|
| + shader = test.getElementsByTagName("shader")
|
| + if not shader:
|
| + return None
|
| + vs = GetElementText(shader[0], "vertshader")
|
| + fs = GetElementText(shader[0], "fragshader")
|
| + if vs and vs != "empty":
|
| + CopyShader(vs, filename, outname)
|
| + if fs and fs != "empty":
|
| + CopyShader(fs, filename, outname)
|
| + data = {
|
| + "name": os.path.basename(outname),
|
| + "compstat": bool(GetBoolElement(test, "compstat")),
|
| + "linkstat": bool(GetBoolElement(test, "linkstat")),
|
| + "testProgram": {
|
| + "vertexShader": vs,
|
| + "fragmentShader": fs,
|
| + },
|
| + }
|
| + attach = test.getElementsByTagName("attach")
|
| + if len(attach) > 0:
|
| + data["attachError"] = GetElementText(attach[0], "attacherror")
|
| + return data
|
| +
|
| + def Process_coverage(self, test, filename, outname):
|
| + Log("coverage Not implemented: %s" % filename)
|
| + self.CopyShaders(test, filename, outname)
|
| +
|
| + def Process_attributes(self, test, filename, outname):
|
| + Log("attributes Not implemented: %s" % filename)
|
| + self.CopyShaders(test, filename, outname)
|
| +
|
| + def Process_fixed(self, test, filename, outname):
|
| + """no need for fixed function tests"""
|
| + self.CopyShaders(test, filename, outname)
|
| +
|
| +
|
| +def main(argv):
|
| + """This is the main function."""
|
| + global VERBOSE
|
| +
|
| + parser = OptionParser()
|
| + parser.add_option(
|
| + "-v", "--verbose", action="store_true",
|
| + help="prints more output.")
|
| +
|
| + (options, args) = parser.parse_args(args=argv)
|
| +
|
| + if len(args) < 1:
|
| + pass # fix me
|
| +
|
| + os.chdir(os.path.dirname(__file__) or '.')
|
| +
|
| + VERBOSE = options.verbose
|
| +
|
| + filename = args[0]
|
| + test_reader = TestReader(filename)
|
| + test_reader.ReadTests(filename)
|
| +
|
| +
|
| +if __name__ == '__main__':
|
| + sys.exit(main(sys.argv[1:]))
|
|
|
| Property changes on: conformance/ogles/process-ogles2-tests.py
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| ## -0,0 +1 ##
|
| +LF
|
| \ No newline at end of property
|
|
|