# -*- coding: utf-8 -*- #------------------------------------------------------------------------- # drawElements Quality Program utilities # -------------------------------------- # # Copyright 2016 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # #------------------------------------------------------------------------- import re import math import random PREAMBLE = """ # WARNING: This file is auto-generated. Do NOT modify it manually, but rather # modify the generating script file. Otherwise changes will be lost! """[1:] class CaseGroup: def __init__(self, name, description, children): self.name = name self.description = description self.children = children class ShaderCase: def __init__(self): pass g_processedCases = {} def indentTextBlock(text, indent): indentStr = indent * "\t" lines = text.split("\n") lines = [indentStr + line for line in lines] lines = [ ["", line][line.strip() != ""] for line in lines] return "\n".join(lines) def writeCase(f, case, indent, prefix): print("\t%s" % (prefix + case.name)) if isinstance(case, CaseGroup): f.write(indentTextBlock('group %s "%s"\n\n' % (case.name, case.description), indent)) for child in case.children: writeCase(f, child, indent + 1, prefix + case.name + ".") f.write(indentTextBlock("\nend # %s\n" % case.name, indent)) else: # \todo [petri] Fix hack. fullPath = prefix + case.name assert (fullPath not in g_processedCases) g_processedCases[fullPath] = None f.write(indentTextBlock(str(case) + "\n", indent)) def writeAllCases(fileName, caseList): # Write all cases to file. print(" %s.." % fileName) f = file(fileName, "wb") f.write(PREAMBLE + "\n") for case in caseList: writeCase(f, case, 0, "") f.close() print("done! (%d cases written)" % len(g_processedCases)) # Template operations. def genValues(inputs, outputs): res = [] for (name, values) in inputs: res.append("input %s = [ %s ];" % (name, " | ".join([str(v) for v in values]).lower())) for (name, values) in outputs: res.append("output %s = [ %s ];" % (name, " | ".join([str(v) for v in values]).lower())) return ("\n".join(res)) def fillTemplate(template, params): s = template for (key, value) in params.items(): m = re.search(r"^(\s*)\$\{\{%s\}\}$" % key, s, re.M) if m is not None: start = m.start(0) end = m.end(0) ws = m.group(1) if value is not None: repl = "\n".join(["%s%s" % (ws, line) for line in value.split("\n")]) s = s[:start] + repl + s[end:] else: s = s[:start] + s[end+1:] # drop the whole line else: s = s.replace("${{%s}}" % key, value) return s # Return shuffled version of list def shuffled(lst): tmp = lst[:] random.shuffle(tmp) return tmp def repeatToLength(lst, toLength): return (toLength / len(lst)) * lst + lst[: toLength % len(lst)] # Helpers to convert a list of Scalar/Vec values into another type. def toFloat(lst): return [Scalar(float(v.x)) for v in lst] def toInt(lst): return [Scalar(int(v.x)) for v in lst] def toBool(lst): return [Scalar(bool(v.x)) for v in lst] def toVec4(lst): return [v.toFloat().toVec4() for v in lst] def toVec3(lst): return [v.toFloat().toVec3() for v in lst] def toVec2(lst): return [v.toFloat().toVec2() for v in lst] def toIVec4(lst): return [v.toInt().toVec4() for v in lst] def toIVec3(lst): return [v.toInt().toVec3() for v in lst] def toIVec2(lst): return [v.toInt().toVec2() for v in lst] def toBVec4(lst): return [v.toBool().toVec4() for v in lst] def toBVec3(lst): return [v.toBool().toVec3() for v in lst] def toBVec2(lst): return [v.toBool().toVec2() for v in lst] def toMat2(lst): return [v.toMat2() for v in lst] def toMat3(lst): return [v.toMat3() for v in lst] def toMat4(lst): return [v.toMat4() for v in lst] # Random value generation. class GenRandom: def __init__(self): pass def uniformVec4(self, count, mn, mx): ret = [Vec4(random.uniform(mn, mx), random.uniform(mn, mx), random.uniform(mn, mx), random.uniform(mn, mx)) for x in xrange(count)] ret[0].x = mn ret[1].x = mx ret[2].x = (mn + mx) * 0.5 return ret def uniformBVec4(self, count): ret = [Vec4(random.random() >= 0.5, random.random() >= 0.5, random.random() >= 0.5, random.random() >= 0.5) for x in xrange(count)] ret[0].x = True ret[1].x = False return ret # def uniform(self, # Math operating on Scalar/Vector types. def glslSign(a): return 0.0 if (a == 0) else +1.0 if (a > 0.0) else -1.0 def glslMod(x, y): return x - y*math.floor(x/y) def glslClamp(x, mn, mx): return mn if (x < mn) else mx if (x > mx) else x class GenMath: @staticmethod def unary(func): return lambda val: val.applyUnary(func) @staticmethod def binary(func): return lambda a, b: (b.expandVec(a)).applyBinary(func, a.expandVec(b)) @staticmethod def frac(val): return val.applyUnary(lambda x: x - math.floor(x)) @staticmethod def exp2(val): return val.applyUnary(lambda x: math.pow(2.0, x)) @staticmethod def log2(val): return val.applyUnary(lambda x: math.log(x, 2.0)) @staticmethod def rsq(val): return val.applyUnary(lambda x: 1.0 / math.sqrt(x)) @staticmethod def sign(val): return val.applyUnary(glslSign) @staticmethod def isEqual(a, b): return Scalar(a.isEqual(b)) @staticmethod def isNotEqual(a, b): return Scalar(not a.isEqual(b)) @staticmethod def step(a, b): return (b.expandVec(a)).applyBinary(lambda edge, x: [1.0, 0.0][x < edge], a.expandVec(b)) @staticmethod def length(a): return a.length() @staticmethod def distance(a, b): return a.distance(b) @staticmethod def dot(a, b): return a.dot(b) @staticmethod def cross(a, b): return a.cross(b) @staticmethod def normalize(a): return a.normalize() @staticmethod def boolAny(a): return a.boolAny() @staticmethod def boolAll(a): return a.boolAll() @staticmethod def boolNot(a): return a.boolNot() # .. class Scalar: def __init__(self, x): self.x = x def applyUnary(self, func): return Scalar(func(self.x)) def applyBinary(self, func, other): return Scalar(func(self.x, other.x)) def isEqual(self, other): assert isinstance(other, Scalar); return (self.x == other.x) def expandVec(self, val): return val def toScalar(self): return Scalar(self.x) def toVec2(self): return Vec2(self.x, self.x) def toVec3(self): return Vec3(self.x, self.x, self.x) def toVec4(self): return Vec4(self.x, self.x, self.x, self.x) def toMat2(self): return self.toVec2().toMat2() def toMat3(self): return self.toVec3().toMat3() def toMat4(self): return self.toVec4().toMat4() def toFloat(self): return Scalar(float(self.x)) def toInt(self): return Scalar(int(self.x)) def toBool(self): return Scalar(bool(self.x)) def getNumScalars(self): return 1 def getScalars(self): return [self.x] def typeString(self): if isinstance(self.x, bool): return "bool" elif isinstance(self.x, int): return "int" elif isinstance(self.x, float): return "float" else: assert False def vec4Swizzle(self): return "" def __str__(self): return "%s" % self.x def length(self): return Scalar(abs(self.x)) def distance(self, v): assert isinstance(v, Scalar) return Scalar(abs(self.x - v.x)) def dot(self, v): assert isinstance(v, Scalar) return Scalar(self.x * v.x) def normalize(self): return Scalar(glslSign(self.x)) def __neg__(self): return Scalar(-self.x) def __add__(self, val): assert isinstance(val, Scalar) return Scalar(self.x + val.x) def __sub__(self, val): return self + (-val) def __mul__(self, val): if isinstance(val, Scalar): return Scalar(self.x * val.x) elif isinstance(val, Vec2): return Vec2(self.x * val.x, self.x * val.y) elif isinstance(val, Vec3): return Vec3(self.x * val.x, self.x * val.y, self.x * val.z) elif isinstance(val, Vec4): return Vec4(self.x * val.x, self.x * val.y, self.x * val.z, self.x * val.w) else: assert False def __div__(self, val): if isinstance(val, Scalar): return Scalar(self.x / val.x) elif isinstance(val, Vec2): return Vec2(self.x / val.x, self.x / val.y) elif isinstance(val, Vec3): return Vec3(self.x / val.x, self.x / val.y, self.x / val.z) elif isinstance(val, Vec4): return Vec4(self.x / val.x, self.x / val.y, self.x / val.z, self.x / val.w) else: assert False class Vec: @staticmethod def fromScalarList(lst): assert (len(lst) >= 1 and len(lst) <= 4) if (len(lst) == 1): return Scalar(lst[0]) elif (len(lst) == 2): return Vec2(lst[0], lst[1]) elif (len(lst) == 3): return Vec3(lst[0], lst[1], lst[2]) else: return Vec4(lst[0], lst[1], lst[2], lst[3]) def isEqual(self, other): assert isinstance(other, Vec); return (self.getScalars() == other.getScalars()) def length(self): return Scalar(math.sqrt(self.dot(self).x)) def normalize(self): return self * Scalar(1.0 / self.length().x) def swizzle(self, indexList): inScalars = self.getScalars() outScalars = map(lambda ndx: inScalars[ndx], indexList) return Vec.fromScalarList(outScalars) def __init__(self): pass class Vec2(Vec): def __init__(self, x, y): assert(x.__class__ == y.__class__) self.x = x self.y = y def applyUnary(self, func): return Vec2(func(self.x), func(self.y)) def applyBinary(self, func, other): return Vec2(func(self.x, other.x), func(self.y, other.y)) def expandVec(self, val): return val.toVec2() def toScalar(self): return Scalar(self.x) def toVec2(self): return Vec2(self.x, self.y) def toVec3(self): return Vec3(self.x, self.y, 0.0) def toVec4(self): return Vec4(self.x, self.y, 0.0, 0.0) def toMat2(self): return Mat2(float(self.x), 0.0, 0.0, float(self.y)); def toFloat(self): return Vec2(float(self.x), float(self.y)) def toInt(self): return Vec2(int(self.x), int(self.y)) def toBool(self): return Vec2(bool(self.x), bool(self.y)) def getNumScalars(self): return 2 def getScalars(self): return [self.x, self.y] def typeString(self): if isinstance(self.x, bool): return "bvec2" elif isinstance(self.x, int): return "ivec2" elif isinstance(self.x, float): return "vec2" else: assert False def vec4Swizzle(self): return ".xyxy" def __str__(self): if isinstance(self.x, bool): return "bvec2(%s, %s)" % (str(self.x).lower(), str(self.y).lower()) elif isinstance(self.x, int): return "ivec2(%i, %i)" % (self.x, self.y) elif isinstance(self.x, float): return "vec2(%s, %s)" % (self.x, self.y) else: assert False def distance(self, v): assert isinstance(v, Vec2) return (self - v).length() def dot(self, v): assert isinstance(v, Vec2) return Scalar(self.x*v.x + self.y*v.y) def __neg__(self): return Vec2(-self.x, -self.y) def __add__(self, val): if isinstance(val, Scalar): return Vec2(self.x + val, self.y + val) elif isinstance(val, Vec2): return Vec2(self.x + val.x, self.y + val.y) else: assert False def __sub__(self, val): return self + (-val) def __mul__(self, val): if isinstance(val, Scalar): val = val.toVec2() assert isinstance(val, Vec2) return Vec2(self.x * val.x, self.y * val.y) def __div__(self, val): if isinstance(val, Scalar): return Vec2(self.x / val.x, self.y / val.x) else: assert isinstance(val, Vec2) return Vec2(self.x / val.x, self.y / val.y) def boolAny(self): return Scalar(self.x or self.y) def boolAll(self): return Scalar(self.x and self.y) def boolNot(self): return Vec2(not self.x, not self.y) class Vec3(Vec): def __init__(self, x, y, z): assert((x.__class__ == y.__class__) and (x.__class__ == z.__class__)) self.x = x self.y = y self.z = z def applyUnary(self, func): return Vec3(func(self.x), func(self.y), func(self.z)) def applyBinary(self, func, other): return Vec3(func(self.x, other.x), func(self.y, other.y), func(self.z, other.z)) def expandVec(self, val): return val.toVec3() def toScalar(self): return Scalar(self.x) def toVec2(self): return Vec2(self.x, self.y) def toVec3(self): return Vec3(self.x, self.y, self.z) def toVec4(self): return Vec4(self.x, self.y, self.z, 0.0) def toMat3(self): return Mat3(float(self.x), 0.0, 0.0, 0.0, float(self.y), 0.0, 0.0, 0.0, float(self.z)); def toFloat(self): return Vec3(float(self.x), float(self.y), float(self.z)) def toInt(self): return Vec3(int(self.x), int(self.y), int(self.z)) def toBool(self): return Vec3(bool(self.x), bool(self.y), bool(self.z)) def getNumScalars(self): return 3 def getScalars(self): return [self.x, self.y, self.z] def typeString(self): if isinstance(self.x, bool): return "bvec3" elif isinstance(self.x, int): return "ivec3" elif isinstance(self.x, float): return "vec3" else: assert False def vec4Swizzle(self): return ".xyzx" def __str__(self): if isinstance(self.x, bool): return "bvec3(%s, %s, %s)" % (str(self.x).lower(), str(self.y).lower(), str(self.z).lower()) elif isinstance(self.x, int): return "ivec3(%i, %i, %i)" % (self.x, self.y, self.z) elif isinstance(self.x, float): return "vec3(%s, %s, %s)" % (self.x, self.y, self.z) else: assert False def distance(self, v): assert isinstance(v, Vec3) return (self - v).length() def dot(self, v): assert isinstance(v, Vec3) return Scalar(self.x*v.x + self.y*v.y + self.z*v.z) def cross(self, v): assert isinstance(v, Vec3) return Vec3(self.y*v.z - v.y*self.z, self.z*v.x - v.z*self.x, self.x*v.y - v.x*self.y) def __neg__(self): return Vec3(-self.x, -self.y, -self.z) def __add__(self, val): if isinstance(val, Scalar): return Vec3(self.x + val, self.y + val) elif isinstance(val, Vec3): return Vec3(self.x + val.x, self.y + val.y, self.z + val.z) else: assert False def __sub__(self, val): return self + (-val) def __mul__(self, val): if isinstance(val, Scalar): val = val.toVec3() assert isinstance(val, Vec3) return Vec3(self.x * val.x, self.y * val.y, self.z * val.z) def __div__(self, val): if isinstance(val, Scalar): return Vec3(self.x / val.x, self.y / val.x, self.z / val.x) else: assert False def boolAny(self): return Scalar(self.x or self.y or self.z) def boolAll(self): return Scalar(self.x and self.y and self.z) def boolNot(self): return Vec3(not self.x, not self.y, not self.z) class Vec4(Vec): def __init__(self, x, y, z, w): assert((x.__class__ == y.__class__) and (x.__class__ == z.__class__) and (x.__class__ == w.__class__)) self.x = x self.y = y self.z = z self.w = w def applyUnary(self, func): return Vec4(func(self.x), func(self.y), func(self.z), func(self.w)) def applyBinary(self, func, other): return Vec4(func(self.x, other.x), func(self.y, other.y), func(self.z, other.z), func(self.w, other.w)) def expandVec(self, val): return val.toVec4() def toScalar(self): return Scalar(self.x) def toVec2(self): return Vec2(self.x, self.y) def toVec3(self): return Vec3(self.x, self.y, self.z) def toVec4(self): return Vec4(self.x, self.y, self.z, self.w) def toMat2(self): return Mat2(float(self.x), float(self.y), float(self.z), float(self.w)) def toMat4(self): return Mat4(float(self.x), 0.0, 0.0, 0.0, 0.0, float(self.y), 0.0, 0.0, 0.0, 0.0, float(self.z), 0.0, 0.0, 0.0, 0.0, float(self.w)); def toFloat(self): return Vec4(float(self.x), float(self.y), float(self.z), float(self.w)) def toInt(self): return Vec4(int(self.x), int(self.y), int(self.z), int(self.w)) def toBool(self): return Vec4(bool(self.x), bool(self.y), bool(self.z), bool(self.w)) def getNumScalars(self): return 4 def getScalars(self): return [self.x, self.y, self.z, self.w] def typeString(self): if isinstance(self.x, bool): return "bvec4" elif isinstance(self.x, int): return "ivec4" elif isinstance(self.x, float): return "vec4" else: assert False def vec4Swizzle(self): return "" def __str__(self): if isinstance(self.x, bool): return "bvec4(%s, %s, %s, %s)" % (str(self.x).lower(), str(self.y).lower(), str(self.z).lower(), str(self.w).lower()) elif isinstance(self.x, int): return "ivec4(%i, %i, %i, %i)" % (self.x, self.y, self.z, self.w) elif isinstance(self.x, float): return "vec4(%s, %s, %s, %s)" % (self.x, self.y, self.z, self.w) else: assert False def distance(self, v): assert isinstance(v, Vec4) return (self - v).length() def dot(self, v): assert isinstance(v, Vec4) return Scalar(self.x*v.x + self.y*v.y + self.z*v.z + self.w*v.w) def __neg__(self): return Vec4(-self.x, -self.y, -self.z, -self.w) def __add__(self, val): if isinstance(val, Scalar): return Vec3(self.x + val, self.y + val) elif isinstance(val, Vec4): return Vec4(self.x + val.x, self.y + val.y, self.z + val.z, self.w + val.w) else: assert False def __sub__(self, val): return self + (-val) def __mul__(self, val): if isinstance(val, Scalar): val = val.toVec4() assert isinstance(val, Vec4) return Vec4(self.x * val.x, self.y * val.y, self.z * val.z, self.w * val.w) def __div__(self, val): if isinstance(val, Scalar): return Vec4(self.x / val.x, self.y / val.x, self.z / val.x, self.w / val.x) else: assert False def boolAny(self): return Scalar(self.x or self.y or self.z or self.w) def boolAll(self): return Scalar(self.x and self.y and self.z and self.w) def boolNot(self): return Vec4(not self.x, not self.y, not self.z, not self.w) # \note Column-major storage. class Mat: def __init__ (self, numCols, numRows, scalars): assert len(scalars) == numRows*numCols self.numCols = numCols self.numRows = numRows self.scalars = scalars @staticmethod def identity (numCols, numRows): scalars = [] for col in range(0, numCols): for row in range(0, numRows): scalars.append(1.0 if col == row else 0.0) return Mat(numCols, numRows, scalars) def get (self, colNdx, rowNdx): assert 0 <= colNdx and colNdx < self.numCols assert 0 <= rowNdx and rowNdx < self.numRows return self.scalars[colNdx*self.numRows + rowNdx] def set (self, colNdx, rowNdx, scalar): assert 0 <= colNdx and colNdx < self.numCols assert 0 <= rowNdx and rowNdx < self.numRows self.scalars[colNdx*self.numRows + rowNdx] = scalar def toMatrix (self, numCols, numRows): res = Mat.identity(numCols, numRows) for col in range(0, min(self.numCols, numCols)): for row in range(0, min(self.numRows, numRows)): res.set(col, row, self.get(col, row)) return res def toMat2 (self): return self.toMatrix(2, 2) def toMat2x3 (self): return self.toMatrix(2, 3) def toMat2x4 (self): return self.toMatrix(2, 4) def toMat3x2 (self): return self.toMatrix(3, 2) def toMat3 (self): return self.toMatrix(3, 3) def toMat3x4 (self): return self.toMatrix(3, 4) def toMat4x2 (self): return self.toMatrix(4, 2) def toMat4x3 (self): return self.toMatrix(4, 3) def toMat4 (self): return self.toMatrix(4, 4) def typeString(self): if self.numRows == self.numCols: return "mat%d" % self.numRows else: return "mat%dx%d" % (self.numCols, self.numRows) def __str__(self): return "%s(%s)" % (self.typeString(), ", ".join([str(s) for s in self.scalars])) def isTypeEqual (self, other): return isinstance(other, Mat) and self.numRows == other.numRows and self.numCols == other.numCols def isEqual(self, other): assert self.isTypeEqual(other) return (self.scalars == other.scalars) def compMul(self, val): assert self.isTypeEqual(val) return Mat(self.numRows, self.numCols, [self.scalars(i) * val.scalars(i) for i in range(self.numRows*self.numCols)]) class Mat2(Mat): def __init__(self, m00, m01, m10, m11): Mat.__init__(self, 2, 2, [m00, m10, m01, m11]) class Mat3(Mat): def __init__(self, m00, m01, m02, m10, m11, m12, m20, m21, m22): Mat.__init__(self, 3, 3, [m00, m10, m20, m01, m11, m21, m02, m12, m22]) class Mat4(Mat): def __init__(self, m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33): Mat.__init__(self, 4, 4, [m00, m10, m20, m30, m01, m11, m21, m31, m02, m12, m22, m32, m03, m13, m23, m33])