Example #1
0
def generate(input, out_src, out_hdr, args):
    with open(input, 'r') as f:
        try:
            yml = yaml.load(f)
        except yaml.YAMLError as exc:
            # show a proper error if YAML parsing fails
            util.setErrorLocation(exc.problem_mark.name,
                                  exc.problem_mark.line - 1)
            util.fmtError('YAML error: {}'.format(exc.problem))
    util.setErrorLocation(input, 1)
    src_root_path = os.path.dirname(input) + '/'
    dst_dir = args['deploy_dir'] + '/'
    if 'options' in yml:
        if 'src_dir' in yml['options']:
            src_root_path += yml['options']['src_dir'] + '/'
        if util.getEnv('target_platform') == 'ios' and 'ios' in yml['options']:
            if 'dst_dir' in yml['options']['ios']:
                dst_dir += yml['options']['ios']['dst_dir'] + '/'
        elif util.getEnv(
                'target_platform') == 'osx' and 'macos' in yml['options']:
            if 'dst_dir' in yml['options']['macos']:
                dst_dir += yml['options']['macos']['dst_dir'] + '/'
        elif 'dst_dir' in yml['options']:
            dst_dir += yml['options']['dst_dir']
        del yml['options']
    if not os.path.exists(dst_dir):
        os.makedirs(dst_dir)
    if check_dirty(src_root_path, input, out_hdr, yml):
        copy_files(src_root_path, dst_dir, yml)
        gen_header(out_hdr, yml)
Example #2
0
def parseOutput(output, lines) :
    '''
    Parse error output lines from FXC, 
    map them to the original source code location and output
    an error message compatible with Xcode or VStudio
    '''
    hasError = False
    hasWarning = False
    outLines = output.splitlines()

    for outLine in outLines :

        # extract generated shader source column, line and message
        # format is 'filename(line,startcol-endcol): msg
        lineStartIndex = outLine.find('(', 0) + 1
        if lineStartIndex == 0 :
            continue
        lineEndIndex = outLine.find(',', lineStartIndex)
        if lineEndIndex == -1 :
            continue
        colStartIndex = lineEndIndex + 1
        colEndIndex = outLine.find('-', colStartIndex)
        if colEndIndex == -1 :
            colEndIndex = outLine.find(')', colStartIndex)
            if colEndIndex == -1 :
                continue
        msgStartIndex = outLine.find(':', colStartIndex+1)
        if msgStartIndex == -1 :
            continue

        colNr = int(outLine[colStartIndex:colEndIndex])
        lineNr = int(outLine[lineStartIndex:lineEndIndex])
        msg = outLine[msgStartIndex:]

        # map to original location
        lineIndex = lineNr - 1
        if lineIndex >= len(lines) :
            lineIndex = len(lines) - 1
        srcPath = lines[lineIndex].path
        srcLineNr = lines[lineIndex].lineNumber
        
        # and output...
        util.setErrorLocation(srcPath, srcLineNr)
        if 'error' in outLine :
            hasError = True
            util.fmtError(msg, False)
        elif 'warning' in outLine :
            hasWarning = True
            util.fmtWarning(msg)

    if hasError :
        for line in lines :
            print(line.content)
        sys.exit(10) 
Example #3
0
 def parseSource(self, fileName):
     f = open(fileName, 'r')
     self.fileName = fileName
     self.lineNumber = 0
     for line in f:
         util.setErrorLocation(self.fileName, self.lineNumber)
         self.parseLine(line)
         self.lineNumber += 1
     f.close()
     if self.current is not None:
         util.fmtError('missing @end at end of file')
Example #4
0
def parseOutput(output, lines):
    '''
    Parse error output lines from FXC, 
    map them to the original source code location and output
    an error message compatible with Xcode or VStudio
    '''
    hasError = False
    hasWarning = False
    outLines = output.splitlines()

    for outLine in outLines:

        # extract generated shader source column, line and message
        # format is 'filename(line,startcol-endcol): msg
        lineStartIndex = outLine.find('(', 0) + 1
        if lineStartIndex == 0:
            continue
        lineEndIndex = outLine.find(',', lineStartIndex)
        if lineEndIndex == -1:
            continue
        colStartIndex = lineEndIndex + 1
        colEndIndex = outLine.find('-', colStartIndex)
        if colEndIndex == -1:
            colEndIndex = outLine.find(')', colStartIndex)
            if colEndIndex == -1:
                continue
        msgStartIndex = outLine.find(':', colStartIndex + 1)
        if msgStartIndex == -1:
            continue

        colNr = int(outLine[colStartIndex:colEndIndex])
        lineNr = int(outLine[lineStartIndex:lineEndIndex])
        msg = outLine[msgStartIndex:]

        # map to original location
        lineIndex = lineNr - 1
        if lineIndex >= len(lines):
            lineIndex = len(lines) - 1
        srcPath = lines[lineIndex].path
        srcLineNr = lines[lineIndex].lineNumber

        # and output...
        util.setErrorLocation(srcPath, srcLineNr)
        if 'error' in outLine:
            hasError = True
            util.fmtError(msg, False)
        elif 'warning' in outLine:
            hasWarning = True
            util.fmtWarning(msg)

    if hasError:
        for line in lines:
            print(line.content)
        sys.exit(10)
Example #5
0
 def resolveDeps(self, shd, dep):
     '''
     Recursively resolve dependencies for a shader.
     '''
     # just add new dependencies at the end of resolvedDeps,
     # and remove dups in a second pass after recursion
     if not dep.name in self.blocks:
         util.setErrorLocation(dep.path, dep.lineNumber)
         util.fmtError("unknown block dependency '{}'".format(dep.name))
     shd.resolvedDeps.append(dep.name)
     for depdep in self.blocks[dep.name].dependencies:
         self.resolveDeps(shd, depdep)
Example #6
0
File: shdc.py Project: floooh/oryol
def compile(input, base_path, slangs):
    util.setErrorLocation(input, 0)
    for slang in slangs:
        if 'glsl' in slang:
            src_slang = 'glsl'
        else:
            src_slang = slang
        src_path = '{}.{}.spv'.format(base_path, src_slang)
        dst_path = '{}.{}'.format(base_path, slang)
        tool = getToolPath()
        cmd = [tool, '-spirv', src_path, '-o', dst_path, '-lang', slang]
        run(cmd)
Example #7
0
 def resolveDeps(self, shd, dep) :
     '''
     Recursively resolve dependencies for a shader.
     '''
     # just add new dependencies at the end of resolvedDeps,
     # and remove dups in a second pass after recursion
     if not dep.name in self.blocks :
         util.setErrorLocation(dep.path, dep.lineNumber)
         util.fmtError("unknown block dependency '{}'".format(dep.name))
     shd.resolvedDeps.append(dep.name)
     for depdep in self.blocks[dep.name].dependencies :
         self.resolveDeps(shd, depdep)
Example #8
0
def compile(input, base_path, slangs):
    util.setErrorLocation(input, 0)
    for slang in slangs:
        if 'glsl' in slang:
            src_slang = 'glsl'
        else:
            src_slang = slang
        src_path = '{}.{}.spv'.format(base_path, src_slang)
        dst_path = '{}.{}'.format(base_path, slang)
        tool = getToolPath()
        cmd = [tool, '-spirv', src_path, '-o', dst_path, '-lang', slang]
        run(cmd)
Example #9
0
 def checkAddUniform(self, uniform, list):
     '''
     Check if uniform already exists in list, if yes
     check if type and binding matches, if not write error.
     If uniform doesn't exist yet in list, add it.
     '''
     listUniform = findByName(uniform.name, list)
     if listUniform is not None:
         # redundant uniform, check if type and binding name match
         if listUniform.type != uniform.type:
             util.setErrorLocation(uniform.filePath, uniform.lineNumber)
             util.fmtError(
                 "uniform type mismatch '{}' vs '{}'".format(
                     uniform.type, listUniform.type), False)
             util.setErrorLocation(listUniform.filePath,
                                   listUniform.lineNumber)
             util.fmtError("uniform type mismatch '{}' vs '{}'".format(
                 listUniform.type, uniform.type))
         if listUniform.bind != uniform.bind:
             util.setErrorLocation(uniform.filePath, uniform.lineNumber)
             util.fmtError(
                 "uniform bind name mismatch '{}' vs '{}'".format(
                     uniform.bind, listUniform.bind), False)
             util.setErrorLocation(listUniform.filePath,
                                   listUniform.lineNumber)
             util.fmtError("uniform bind name mismatch '{}' vs '{}'".format(
                 listUniform.bind, uniform.bind))
     else:
         # new uniform from block, add to list
         list.append(uniform)
Example #10
0
    def resolveBundleUniforms(self, bundle) :
        '''
        Gathers all uniforms from all shaders in the bundle.
        '''
        for program in bundle.programs :
            if program.vs not in self.vertexShaders :
                util.setErrorLocation(program.filePath, program.lineNumber)
                util.fmtError("unknown vertex shader '{}'".format(program.vs))
            for uniform in self.vertexShaders[program.vs].uniforms :
                self.checkAddUniform(uniform, bundle.uniforms)

            if program.fs not in self.fragmentShaders :
                util.setErrorLocation(program.filePath, program.lineNumber)
                util.fmtError("unknown fragment shader '{}'".format(program.fs))
            for uniform in self.fragmentShaders[program.fs].uniforms :
                self.checkAddUniform(uniform, bundle.uniforms)
Example #11
0
    def parseSource(self, fileName) :
        '''
        Parse a single file and populate shader lib
        '''
        f = open(fileName, 'r')
        self.fileName = fileName
        self.lineNumber = 0
        for line in f :
            util.setErrorLocation(self.fileName, self.lineNumber)
            self.parseLine(line)
            self.lineNumber += 1
        f.close()

        # all blocks must be closed
        if self.current is not None :
            util.fmtError('missing @end at end of file')
Example #12
0
 def generateShaderSources(self):
     for shd in self.shaders:
         lines = []
         for l in shd.lines:
             # @include statement?
             if l.include:
                 if l.include not in self.blocks:
                     util.setErrorLocation(incl.path, incl.lineNumber)
                     util.fmtError(
                         "included block '{}' doesn't exist".format(
                             incl.name))
                 for lb in self.blocks[l.include].lines:
                     lines.append(lb)
             else:
                 lines.append(l)
         shd.generatedSource = lines
Example #13
0
    def parseSource(self, fileName):
        '''
        Parse a single file and populate shader lib
        '''
        f = open(fileName, 'r')
        self.fileName = fileName
        self.lineNumber = 0
        for line in f:
            util.setErrorLocation(self.fileName, self.lineNumber)
            self.parseLine(line)
            self.lineNumber += 1
        f.close()

        # all blocks must be closed
        if self.current is not None:
            util.fmtError('missing @end at end of file')
Example #14
0
def generate(input, out_src, out_hdr, args):
    with open(input, 'r') as f:
        try:
            yml = yaml.load(f)
        except yaml.YAMLError as exc:
            # show a proper error if YAML parsing fails
            util.setErrorLocation(exc.problem_mark.name, exc.problem_mark.line-1)
            util.fmtError('YAML error: {}'.format(exc.problem))
    src_root_path = os.path.dirname(input) + '/'
    if 'root' in yml:
        src_root_path += yml['root'] + '/'
    deploy_dir = args['deploy_dir'] + '/'
    if not os.path.exists(deploy_dir):
        os.makedirs(deploy_dir)
    if check_dirty(src_root_path, input, out_hdr, yml):
        copy_files(src_root_path, deploy_dir, yml)
        gen_header(out_hdr, yml)
Example #15
0
    def resolveBundleUniforms(self, bundle):
        '''
        Gathers all uniforms from all shaders in the bundle.
        '''
        for program in bundle.programs:
            if program.vs not in self.vertexShaders:
                util.setErrorLocation(program.filePath, program.lineNumber)
                util.fmtError("unknown vertex shader '{}'".format(program.vs))
            for uniform in self.vertexShaders[program.vs].uniforms:
                self.checkAddUniform(uniform, bundle.uniforms)

            if program.fs not in self.fragmentShaders:
                util.setErrorLocation(program.filePath, program.lineNumber)
                util.fmtError("unknown fragment shader '{}'".format(
                    program.fs))
            for uniform in self.fragmentShaders[program.fs].uniforms:
                self.checkAddUniform(uniform, bundle.uniforms)
Example #16
0
def parseOutput(output, lines) :
    '''
    Parse error output lines from the GLSL reference compiler,
    map them to the original source code location and output
    an error message compatible with Xcode or VStudio
    '''
    hasError = False
    outLines = output.splitlines()
    for outLine in outLines :
        if outLine.startswith('ERROR: ') :
            hasError = True

            # extract generated shader source column, line and message
            colStartIndex = 7
            colEndIndex = outLine.find(':', colStartIndex)
            if colEndIndex == -1 :
                continue
            lineStartIndex = colEndIndex + 1
            lineEndIndex = outLine.find(':', lineStartIndex)
            if lineEndIndex == -1 :
                continue
            msgStartIndex = lineEndIndex + 1
            colNr = int(outLine[colStartIndex:colEndIndex])
            lineNr = int(outLine[lineStartIndex:lineEndIndex])
            msg = outLine[msgStartIndex:]

            # map to original location
            lineIndex = lineNr - 1
            if lineIndex >= len(lines) :
                lineIndex = len(lines) - 1
            srcPath = lines[lineIndex].path
            srcLineNr = lines[lineIndex].lineNumber
            
            # and output...
            util.setErrorLocation(srcPath, srcLineNr)
            util.fmtError(msg, False)
            
    if hasError :
        for line in lines :
            print "{}\n".format(line.content)
        util.fmtError("Aborting.")
Example #17
0
def parseOutput(output, lines):
    hasError = False
    hasWarnings = False
    outLines = output.splitlines()

    for outLine in outLines:
        if 'error:' in outLine or 'warning:' in outLine or 'note:' in outLine:
            tokens = outLine.split(':')
            metalSrcPath = tokens[0]
            lineNr = int(tokens[1])
            colNr = int(tokens[2])
            msgType = tokens[3]
            msg = tokens[4]

            if msgType == ' error':
                hasError = True
            if msgType == ' warning':
                hasWarning = True

            # map to original location
            lineIndex = lineNr - 1
            if lineIndex >= len(lines):
                lineIndex = len(lines) - 1
            srcPath = lines[lineIndex].path
            srcLineNr = lines[lineIndex].lineNumber

            # and output...
            util.setErrorLocation(srcPath, srcLineNr)
            util.fmtError(msg, False)

    if hasError:
        for outLine in outLines:
            print(outLine)
        for line in lines:
            print(line.content)
        sys.exit(10)
Example #18
0
def parseOutput(output, lines) :
    hasError = False
    hasWarnings = False
    outLines = output.splitlines()

    for outLine in outLines :
        if 'error:' in outLine or 'warning:' in outLine or 'note:' in outLine:
            tokens = outLine.split(':')
            metalSrcPath = tokens[0]
            lineNr = int(tokens[1])
            colNr = int(tokens[2])
            msgType = tokens[3]
            msg = tokens[4]

            if msgType == ' error':
                hasError = True
            if msgType == ' warning':
                hasWarning = True

            # map to original location
            lineIndex = lineNr - 1
            if lineIndex >= len(lines) :
                lineIndex = len(lines) - 1
            srcPath = lines[lineIndex].path
            srcLineNr = lines[lineIndex].lineNumber

            # and output...
            util.setErrorLocation(srcPath, srcLineNr)
            util.fmtError(msg, False)

    if hasError :
        for outLine in outLines :
            print(outLine)
        for line in lines :
            print(line.content)
        sys.exit(10) 
Example #19
0
 def checkAddUniform(self, uniform, list) :
     '''
     Check if uniform already exists in list, if yes
     check if type and binding matches, if not write error.
     If uniform doesn't exist yet in list, add it.
     '''
     listUniform = findByName(uniform.name, list)
     if listUniform is not None:
         # redundant uniform, check if type and binding name match
         if listUniform.type != uniform.type :
             util.setErrorLocation(uniform.filePath, uniform.lineNumber)
             util.fmtError("uniform type mismatch '{}' vs '{}'".format(uniform.type, listUniform.type), False)
             util.setErrorLocation(listUniform.filePath, listUniform.lineNumber)
             util.fmtError("uniform type mismatch '{}' vs '{}'".format(listUniform.type, uniform.type))
         if listUniform.bind != uniform.bind :
             util.setErrorLocation(uniform.filePath, uniform.lineNumber)
             util.fmtError("uniform bind name mismatch '{}' vs '{}'".format(uniform.bind, listUniform.bind), False)
             util.setErrorLocation(listUniform.filePath, listUniform.lineNumber)
             util.fmtError("uniform bind name mismatch '{}' vs '{}'".format(listUniform.bind, uniform.bind))
     else :
         # new uniform from block, add to list
         list.append(uniform)
Example #20
0
    def validate(self, slangs):
        '''
        Runs additional validation check after programs are resolved and before
        shader code is generated:

        - check whether each vs and fs is part of a program
        - check vertex shader inputs for valid types and names
        - check whether vertex shader output matches fragment shader input
        '''
        for shd in self.shaders:
            for prog in self.programs.values():
                prog_shd = prog.vs if shd.getTag() == 'vs' else prog.fs
                if shd.name == prog_shd:
                    break
            else:
                util.setErrorLocation(shd.lines[0].path,
                                      shd.lines[0].lineNumber)
                util.fmtError(
                    "vertex shader '{}' is not part of a program".format(
                        shd.name), False)
                fatalError = True
        for slang in slangs:
            for vs in self.vertexShaders.values():
                refl = vs.slReflection[slang]
                util.setErrorLocation(vs.lines[0].path, vs.lines[0].lineNumber)
                vs_inputs = refl['inputs']
                for vs_input in vs_inputs:
                    if vs_input['name'] not in validVsInNames:
                        util.fmtError(
                            "invalid vertex shader input name '{}', must be ({})"
                            .format(vs_input['name'],
                                    ','.join(validVsInNames)))
                    if vs_input['type'] not in validInOutTypes:
                        util.fmtError(
                            "invalid vertex shader input type '{}', must be ({})"
                            .format(vs_input['type'],
                                    ','.join(validInOutTypes)))
                for ub in refl['uniform_blocks']:
                    for m in ub['members']:
                        validTypes = validUniformTypes if m[
                            'num'] == 1 else validUniformArrayTypes
                        if m['type'] not in validTypes:
                            util.fmtError(
                                "invalid uniform block member type '{}', must be ({})"
                                .format(m['type'], ','.join(validTypes)))
            for fs in self.fragmentShaders.values():
                refl = fs.slReflection[slang]
                util.setErrorLocation(fs.lines[0].path, fs.lines[0].lineNumber)
                for ub in refl['uniform_blocks']:
                    for m in ub['members']:
                        validTypes = validUniformTypes if m[
                            'num'] == 1 else validUniformArrayTypes
                        if m['type'] not in validTypes:
                            util.fmtError(
                                "invalid uniform block member type '{}', must be ({})"
                                .format(m['type'], ','.join(validTypes)))
            for prog in self.programs.values():
                vs = self.vertexShaders[prog.vs]
                fs = self.fragmentShaders[prog.fs]
                vs_outputs = vs.slReflection[slang]['outputs']
                fs_inputs = fs.slReflection[slang]['inputs']
                vs_fs_error = False
                if len(vs_outputs) == len(fs_inputs):
                    for vs_out in vs_outputs:
                        in_out_match = False
                        for fs_in in fs_inputs:
                            if (vs_out['name']
                                    == fs_in['name']) and (vs_out['type']
                                                           == fs_in['type']):
                                in_out_match = True
                                break
                        if not in_out_match:
                            vs_fs_error = True
                if vs_fs_error:
                    # number of inputs/outputs don't match
                    vs_fs_error = True
                    util.setErrorLocation(vs.lines[0].path,
                                          vs.lines[0].lineNumber)
                    util.fmtError(
                        "outputs of vs '{}' don't match inputs of fs '{}' (unused items might have been removed)"
                        .format(vs.name, fs.name))