Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(64)

Unified Diff: conformance/ogles/process-ogles2-tests.py

Issue 41993002: Add ToT WebGL conformance tests : part 9 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/deps/third_party/webgl/sdk/tests/
Patch Set: Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « conformance/ogles/ogles-utils.js ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
« no previous file with comments | « conformance/ogles/ogles-utils.js ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698