예제 #1
0
//
// Thread entry point, for non-linking asynchronous mode.
//
// Return 0 for failure, 1 for success.
//
unsigned int CompileShaders(void*)
{
    glslang::TWorkItem* workItem;
    while (Worklist.remove(workItem)) {
        ShHandle compiler = ShConstructCompiler(FindLanguage(workItem->name), Options);
        if (compiler == 0)
            return 0;

        CompileFile(workItem->name.c_str(), compiler);

        if (! (Options & EOptionSuppressInfolog))
            workItem->results = ShGetInfoLog(compiler);

        ShDestruct(compiler);
    }

    return 0;
}
예제 #2
0
//
// Do file IO part of compile and link, handing off the pure
// API/programmatic mode to CompileAndLinkShaderUnits(), which can
// be put in a loop for testing memory footprint and performance.
//
// This is just for linking mode: meaning all the shaders will be put into the
// the same program linked together.
//
// This means there are a limited number of work items (not multi-threading mode)
// and that the point is testing at the linking level. Hence, to enable
// performance and memory testing, the actual compile/link can be put in
// a loop, independent of processing the work items and file IO.
//
void CompileAndLinkShaderFiles()
{
    std::vector<ShaderCompUnit> compUnits;

    // Transfer all the work items from to a simple list of
    // of compilation units.  (We don't care about the thread
    // work-item distribution properties in this path, which
    // is okay due to the limited number of shaders, know since
    // they are all getting linked together.)
    glslang::TWorkItem* workItem;
    while (Worklist.remove(workItem)) {
        ShaderCompUnit compUnit(
            FindLanguage(workItem->name),
            workItem->name,
            ReadFileData(workItem->name.c_str())
        );

        if (! compUnit.text) {
            usage();
            return;
        }

        compUnits.push_back(compUnit);
    }

    // Actual call to programmatic processing of compile and link,
    // in a loop for testing memory and performance.  This part contains
    // all the perf/memory that a programmatic consumer will care about.
    for (int i = 0; i < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++i) {
        for (int j = 0; j < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++j)
           CompileAndLinkShaderUnits(compUnits);

        if (Options & EOptionMemoryLeakMode)
            glslang::OS_DumpMemoryCounters();
    }

    for (auto it = compUnits.begin(); it != compUnits.end(); ++it)
        FreeFileData(it->text);
}
예제 #3
0
int C_DECL main(int argc, char* argv[])
{
    ProcessArguments(argc, argv);

    if (Options & EOptionDumpConfig) {
        printf("%s", DefaultConfig);
        if (Worklist.empty())
            return ESuccess;
    }

    if (Options & EOptionDumpVersions) {
        printf("Glslang Version: %s %s\n", GLSLANG_REVISION, GLSLANG_DATE);
        printf("ESSL Version: %s\n", glslang::GetEsslVersionString());
        printf("GLSL Version: %s\n", glslang::GetGlslVersionString());
        std::string spirvVersion;
        glslang::GetSpirvVersion(spirvVersion);
        printf("SPIR-V Version %s\n", spirvVersion.c_str());
        printf("GLSL.std.450 Version %d, Revision %d\n", GLSLstd450Version, GLSLstd450Revision);
        if (Worklist.empty())
            return ESuccess;
    }

    if (Worklist.empty()) {
        usage();
    }

    ProcessConfigFile();

    //
    // Two modes:
    // 1) linking all arguments together, single-threaded, new C++ interface
    // 2) independent arguments, can be tackled by multiple asynchronous threads, for testing thread safety, using the old handle interface
    //
    if (Options & EOptionLinkProgram ||
        Options & EOptionOutputPreprocessed) {
        glslang::InitializeProcess();
        CompileAndLinkShaders();
        glslang::FinalizeProcess();
    } else {
        ShInitialize();

        bool printShaderNames = Worklist.size() > 1;

        if (Options & EOptionMultiThreaded) {
            const int NumThreads = 16;
            void* threads[NumThreads];
            for (int t = 0; t < NumThreads; ++t) {
                threads[t] = glslang::OS_CreateThread(&CompileShaders);
                if (! threads[t]) {
                    printf("Failed to create thread\n");
                    return EFailThreadCreate;
                }
            }
            glslang::OS_WaitForAllThreads(threads, NumThreads);
        } else
            CompileShaders(0);

        // Print out all the resulting infologs
        for (int w = 0; w < NumWorkItems; ++w) {
            if (Work[w]) {
                if (printShaderNames)
                    PutsIfNonEmpty(Work[w]->name.c_str());
                PutsIfNonEmpty(Work[w]->results.c_str());
                delete Work[w];
            }
        }

        ShFinalize();
    }

    if (CompileFailed)
        return EFailCompile;
    if (LinkFailed)
        return EFailLink;

    return 0;
}
예제 #4
0
//
// For linking mode: Will independently parse each item in the worklist, but then put them
// in the same program and link them together.
//
// Uses the new C++ interface instead of the old handle-based interface.
//
void CompileAndLinkShaders()
{
    // keep track of what to free
    std::list<glslang::TShader*> shaders;
    
    EShMessages messages = EShMsgDefault;
    SetMessageOptions(messages);

    //
    // Per-shader processing...
    //

    glslang::TProgram& program = *new glslang::TProgram;
    glslang::TWorkItem* workItem;
    while (Worklist.remove(workItem)) {
        EShLanguage stage = FindLanguage(workItem->name);
        glslang::TShader* shader = new glslang::TShader(stage);
        shaders.push_back(shader);
    
        char** shaderStrings = ReadFileData(workItem->name.c_str());
        if (! shaderStrings) {
            usage();
            delete &program;

            return;
        }
        const int defaultVersion = Options & EOptionDefaultDesktop? 110: 100;

        shader->setStrings(shaderStrings, 1);
        if (Options & EOptionOutputPreprocessed) {
            std::string str;
            if (shader->preprocess(&Resources, defaultVersion, ENoProfile, false, false,
                                   messages, &str, glslang::TShader::ForbidInclude())) {
                PutsIfNonEmpty(str.c_str());
            } else {
                CompileFailed = true;
            }
            StderrIfNonEmpty(shader->getInfoLog());
            StderrIfNonEmpty(shader->getInfoDebugLog());
            FreeFileData(shaderStrings);
            continue;
        }
        if (! shader->parse(&Resources, defaultVersion, false, messages))
            CompileFailed = true;

        program.addShader(shader);

        if (! (Options & EOptionSuppressInfolog)) {
            PutsIfNonEmpty(workItem->name.c_str());
            PutsIfNonEmpty(shader->getInfoLog());
            PutsIfNonEmpty(shader->getInfoDebugLog());
        }

        FreeFileData(shaderStrings);
    }

    //
    // Program-level processing...
    //

    if (! (Options & EOptionOutputPreprocessed) && ! program.link(messages))
        LinkFailed = true;

    if (! (Options & EOptionSuppressInfolog)) {
        PutsIfNonEmpty(program.getInfoLog());
        PutsIfNonEmpty(program.getInfoDebugLog());
    }

    if (Options & EOptionDumpReflection) {
        program.buildReflection();
        program.dumpReflection();
    }

    if (Options & EOptionSpv) {
        if (CompileFailed || LinkFailed)
            printf("SPIR-V is not generated for failed compile or link\n");
        else {
            for (int stage = 0; stage < EShLangCount; ++stage) {
                if (program.getIntermediate((EShLanguage)stage)) {
                    std::vector<unsigned int> spirv;
                    glslang::GlslangToSpv(*program.getIntermediate((EShLanguage)stage), spirv);
                    glslang::OutputSpv(spirv, GetBinaryName((EShLanguage)stage));
                    if (Options & EOptionHumanReadableSpv) {
                        spv::Parameterize();
                        spv::Disassemble(std::cout, spirv);
                    }
                }
            }
        }
    }

    // Free everything up, program has to go before the shaders
    // because it might have merged stuff from the shaders, and
    // the stuff from the shaders has to have its destructors called
    // before the pools holding the memory in the shaders is freed.
    delete &program;
    while (shaders.size() > 0) {
        delete shaders.back();
        shaders.pop_back();
    }
}
예제 #5
0
//
// Do all command-line argument parsing.  This includes building up the work-items
// to be processed later, and saving all the command-line options.
//
// Does not return (it exits) if command-line is fatally flawed.
//
void ProcessArguments(int argc, char* argv[])
{
    ExecutableName = argv[0];
    NumWorkItems = argc;  // will include some empties where the '-' options were, but it doesn't matter, they'll be 0
    Work = new glslang::TWorkItem*[NumWorkItems];
    for (int w = 0; w < NumWorkItems; ++w)
        Work[w] = 0;

    argc--;
    argv++;    
    for (; argc >= 1; argc--, argv++) {
        if (argv[0][0] == '-') {
            switch (argv[0][1]) {
            case 'H':
                Options |= EOptionHumanReadableSpv;
                // fall through to -V
            case 'V':
                Options |= EOptionSpv;
                Options |= EOptionVulkanRules;
                Options |= EOptionLinkProgram;
                break;
            case 'G':
                Options |= EOptionSpv;
                Options |= EOptionLinkProgram;
                break;
            case 'E':
                Options |= EOptionOutputPreprocessed;
                break;
            case 'c':
                Options |= EOptionDumpConfig;
                break;
            case 'd':
                Options |= EOptionDefaultDesktop;
                break;
            case 'h':
                usage();
                break;
            case 'i':
                Options |= EOptionIntermediate;
                break;
            case 'l':
                Options |= EOptionLinkProgram;
                break;
            case 'm':
                Options |= EOptionMemoryLeakMode;
                break;
            case 'o':
                binaryFileName = argv[1];
                if (argc > 0) {
                    argc--;
                    argv++;
                } else
                    Error("no <file> provided for -o");
                break;
            case 'q':
                Options |= EOptionDumpReflection;
                break;
            case 'r':
                Options |= EOptionRelaxedErrors;
                break;
            case 's':
                Options |= EOptionSuppressInfolog;
                break;
            case 't':
                #ifdef _WIN32
                    Options |= EOptionMultiThreaded;
                #endif
                break;
            case 'v':
                Options |= EOptionDumpVersions;
                break;
            case 'w':
                Options |= EOptionSuppressWarnings;
                break;
            default:
                usage();
                break;
            }
        } else {
            std::string name(argv[0]);
            if (! SetConfigFile(name)) {
                Work[argc] = new glslang::TWorkItem(name);
                Worklist.add(Work[argc]);
            }
        }
    }

    // Make sure that -E is not specified alongside linking (which includes SPV generation)
    if ((Options & EOptionOutputPreprocessed) && (Options & EOptionLinkProgram))
        Error("can't use -E when linking is selected");

    // -o makes no sense if there is no target binary
    if (binaryFileName && (Options & EOptionSpv) == 0)
        Error("no binary generation requested (e.g., -V)");
}
예제 #6
0
int C_DECL main(int argc, char* argv[]) {
	if (argc < 6) {
		usage();
		return 1;
	}

	const char* tempdir = argv[4];
	
	//Options |= EOptionHumanReadableSpv;
	Options |= EOptionSpv;
	Options |= EOptionLinkProgram;
	//Options |= EOptionSuppressInfolog;

	NumWorkItems = 1;
	Work = new glslang::TWorkItem*[NumWorkItems];
	Work[0] = 0;

	std::string name(argv[2]);
	if (!SetConfigFile(name)) {
		Work[0] = new glslang::TWorkItem(name);
		Worklist.add(Work[0]);
	}

	ProcessConfigFile();

	glslang::InitializeProcess();
	
	KrafixIncluder includer(name);
	krafix::Target target;
	target.system = getSystem(argv[5]);
	target.es = false;
	if (strcmp(argv[1], "d3d9") == 0) {
		target.lang = krafix::HLSL;
		target.version = 9;
		CompileAndLinkShaders(target, argv[3], tempdir, includer);
	}
	else if (strcmp(argv[1], "d3d11") == 0) {
		target.lang = krafix::HLSL;
		target.version = 11;
		CompileAndLinkShaders(target, argv[3], tempdir, includer);
	}
	else if (strcmp(argv[1], "glsl") == 0) {
		target.lang = krafix::GLSL;
		if (target.system == krafix::Linux) target.version = 100;
		else target.version = 330;
		CompileAndLinkShaders(target, argv[3], tempdir, includer);
	}
	else if (strcmp(argv[1], "essl") == 0) {
		target.lang = krafix::GLSL;
		target.version = 100;
		target.es = true;
		CompileAndLinkShaders(target, argv[3], tempdir, includer);
	}
	else if (strcmp(argv[1], "agal") == 0) {
		target.lang = krafix::AGAL;
		target.version = 100;
		target.es = true;
		CompileAndLinkShaders(target, argv[3], tempdir, includer);
	}
	else if (strcmp(argv[1], "metal") == 0) {
		target.lang = krafix::Metal;
		target.version = 1;
		CompileAndLinkShaders(target, argv[3], tempdir, includer);
	}
	else if (strcmp(argv[1], "varlist") == 0) {
		target.lang = krafix::VarList;
		target.version = 1;
		CompileAndLinkShaders(target, argv[3], tempdir, includer);
	}
	else {
		std::cout << "Unknown profile " << argv[1] << std::endl;
		CompileFailed = true;
	}

	glslang::FinalizeProcess();

	if (CompileFailed)
		return EFailCompile;
	if (LinkFailed)
		return EFailLink;

	return 0;
}
예제 #7
0
//
// For linking mode: Will independently parse each item in the worklist, but then put them
// in the same program and link them together.
//
// Uses the new C++ interface instead of the old handle-based interface.
//
void CompileAndLinkShaders(krafix::Target target, const char* filename, const char* tempdir, const glslang::TShader::Includer& includer)
{
    // keep track of what to free
    std::list<glslang::TShader*> shaders;
    
    EShMessages messages = EShMsgDefault;
    SetMessageOptions(messages);

    //
    // Per-shader processing...
    //

    glslang::TProgram& program = *new glslang::TProgram;
    glslang::TWorkItem* workItem;
    while (Worklist.remove(workItem)) {
        EShLanguage stage = FindLanguage(workItem->name);
        glslang::TShader* shader = new glslang::TShader(stage);
        shaders.push_back(shader);
    
        char** shaderStrings = ReadFileData(workItem->name.c_str());
        if (! shaderStrings) {
            usage();
            delete &program;

            return;
        }
        const int defaultVersion = Options & EOptionDefaultDesktop? 110: 100;

        shader->setStrings(shaderStrings, 1);
        if (Options & EOptionOutputPreprocessed) {
            std::string str;
            if (shader->preprocess(&Resources, defaultVersion, ENoProfile, false, false,
                                   messages, &str, includer)) {
                PutsIfNonEmpty(str.c_str());
            } else {
                CompileFailed = true;
            }
            StderrIfNonEmpty(shader->getInfoLog());
            StderrIfNonEmpty(shader->getInfoDebugLog());
            FreeFileData(shaderStrings);
            continue;
        }
		if (! shader->parse(&Resources, defaultVersion, ENoProfile, false, false, messages, includer))
            CompileFailed = true;

        program.addShader(shader);

        if (! (Options & EOptionSuppressInfolog)) {
            //PutsIfNonEmpty(workItem->name.c_str());
            PutsIfNonEmpty(shader->getInfoLog());
            PutsIfNonEmpty(shader->getInfoDebugLog());
        }

        FreeFileData(shaderStrings);
    }

    //
    // Program-level processing...
    //

    if (! (Options & EOptionOutputPreprocessed) && ! program.link(messages))
        LinkFailed = true;

    if (! (Options & EOptionSuppressInfolog)) {
        PutsIfNonEmpty(program.getInfoLog());
        PutsIfNonEmpty(program.getInfoDebugLog());
    }

    if (Options & EOptionDumpReflection) {
        program.buildReflection();
        program.dumpReflection();
    }

    if (Options & EOptionSpv) {
        if (CompileFailed || LinkFailed)
            printf("SPIRV is not generated for failed compile or link\n");
        else {
            for (int stage = 0; stage < EShLangCount; ++stage) {
                if (program.getIntermediate((EShLanguage)stage)) {
                    std::vector<unsigned int> spirv;
                    glslang::GlslangToSpv(*program.getIntermediate((EShLanguage)stage), spirv);
					krafix::Translator* translator = NULL;
					std::map<std::string, int> attributes;
					switch (target.lang) {
					case krafix::GLSL:
						translator = new krafix::GlslTranslator(spirv, (EShLanguage)stage);
						break;
					case krafix::HLSL:
						translator = new krafix::HlslTranslator(spirv, (EShLanguage)stage);
						break;
					case krafix::Metal:
						translator = new krafix::MetalTranslator(spirv, (EShLanguage)stage);
						break;
					case krafix::AGAL:
						translator = new krafix::AgalTranslator(spirv, (EShLanguage)stage);
						break;
					case krafix::VarList:
						translator = new krafix::VarListTranslator(spirv, (EShLanguage)stage);
						break;
					}
					
					if (target.lang == krafix::HLSL && target.system != krafix::Unity) {
						std::string temp = std::string(tempdir) + "/" + removeExtension(extractFilename(workItem->name)) + ".hlsl";
						translator->outputCode(target, temp.c_str(), attributes);
						if (target.version == 9) {
							compileHLSLToD3D9(temp.c_str(), filename, attributes, (EShLanguage)stage);
						}
						else {
							compileHLSLToD3D11(temp.c_str(), filename, attributes, (EShLanguage)stage);
						}
					}
					else {
						translator->outputCode(target, filename, attributes);
					}

					delete translator;
                    
                    //glslang::OutputSpv(spirv, GetBinaryName((EShLanguage)stage));
                    if (Options & EOptionHumanReadableSpv) {
                        spv::Parameterize();
                        spv::Disassemble(std::cout, spirv);
                    }
                }
            }
        }
    }

    // Free everything up, program has to go before the shaders
    // because it might have merged stuff from the shaders, and
    // the stuff from the shaders has to have its destructors called
    // before the pools holding the memory in the shaders is freed.
    delete &program;
    while (shaders.size() > 0) {
        delete shaders.back();
        shaders.pop_back();
    }
}
예제 #8
0
//
// Do all command-line argument parsing.  This includes building up the work-items
// to be processed later, and saving all the command-line options.
//
// Does not return (it exits) if command-line is fatally flawed.
//
void ProcessArguments(int argc, char* argv[])
{
    baseSamplerBinding.fill(0);
    baseTextureBinding.fill(0);
    baseImageBinding.fill(0);
    baseUboBinding.fill(0);

    ExecutableName = argv[0];
    NumWorkItems = argc;  // will include some empties where the '-' options were, but it doesn't matter, they'll be 0
    Work = new glslang::TWorkItem*[NumWorkItems];
    for (int w = 0; w < NumWorkItems; ++w)
        Work[w] = 0;

    argc--;
    argv++;
    for (; argc >= 1; argc--, argv++) {
        if (argv[0][0] == '-') {
            switch (argv[0][1]) {
            case '-':
                {
                    std::string lowerword(argv[0]+2);
                    std::transform(lowerword.begin(), lowerword.end(), lowerword.begin(), ::tolower);

                    // handle --word style options
                    if (lowerword == "shift-sampler-bindings" || // synonyms
                        lowerword == "shift-sampler-binding"  ||
                        lowerword == "ssb") {
                        ProcessBindingBase(argc, argv, baseSamplerBinding);
                    } else if (lowerword == "shift-texture-bindings" ||  // synonyms
                               lowerword == "shift-texture-binding"  ||
                               lowerword == "stb") {
                        ProcessBindingBase(argc, argv, baseTextureBinding);
                    } else if (lowerword == "shift-image-bindings" ||  // synonyms
                               lowerword == "shift-image-binding"  ||
                               lowerword == "sib") {
                        ProcessBindingBase(argc, argv, baseImageBinding);
                    } else if (lowerword == "shift-ubo-bindings" ||  // synonyms
                               lowerword == "shift-ubo-binding"  ||
                               lowerword == "sub") {
                        ProcessBindingBase(argc, argv, baseUboBinding);
                    } else if (lowerword == "auto-map-bindings" ||  // synonyms
                               lowerword == "auto-map-binding"  ||
                               lowerword == "amb") {
                        Options |= EOptionAutoMapBindings;
                    } else if (lowerword == "flatten-uniform-arrays" || // synonyms
                               lowerword == "flatten-uniform-array"  ||
                               lowerword == "fua") {
                        Options |= EOptionFlattenUniformArrays;
                    } else if (lowerword == "no-storage-format" || // synonyms
                               lowerword == "nsf") {
                        Options |= EOptionNoStorageFormat;
                    } else if (lowerword == "source-entrypoint" || // synonyms
                               lowerword == "sep") {
                        sourceEntryPointName = argv[1];
                        if (argc > 0) {
                            argc--;
                            argv++;
                        } else
                            Error("no <entry-point> provided for --source-entrypoint");
                        break;
                    } else if (lowerword == "keep-uncalled" || // synonyms
                               lowerword == "ku") {
                        Options |= EOptionKeepUncalled;
                    } else {
                        usage();
                    }
                }
                break;
            case 'H':
                Options |= EOptionHumanReadableSpv;
                if ((Options & EOptionSpv) == 0) {
                    // default to Vulkan
                    Options |= EOptionSpv;
                    Options |= EOptionVulkanRules;
                    Options |= EOptionLinkProgram;
                }
                break;
            case 'V':
                Options |= EOptionSpv;
                Options |= EOptionVulkanRules;
                Options |= EOptionLinkProgram;
                break;
            case 'S':
                shaderStageName = argv[1];
                if (argc > 0) {
                    argc--;
                    argv++;
                }
                else
                    Error("no <stage> specified for -S");
                break;
            case 'G':
                Options |= EOptionSpv;
                Options |= EOptionLinkProgram;
                // undo a -H default to Vulkan
                Options &= ~EOptionVulkanRules;
                break;
            case 'E':
                Options |= EOptionOutputPreprocessed;
                break;
            case 'c':
                Options |= EOptionDumpConfig;
                break;
            case 'C':
                Options |= EOptionCascadingErrors;
                break;
            case 'd':
                Options |= EOptionDefaultDesktop;
                break;
            case 'D':
                Options |= EOptionReadHlsl;
                break;
            case 'e':
                // HLSL todo: entry point handle needs much more sophistication.
                // This is okay for one compilation unit with one entry point.
                entryPointName = argv[1];
                if (argc > 0) {
                    argc--;
                    argv++;
                } else
                    Error("no <entry-point> provided for -e");
                break;
            case 'h':
                usage();
                break;
            case 'i':
                Options |= EOptionIntermediate;
                break;
            case 'l':
                Options |= EOptionLinkProgram;
                break;
            case 'm':
                Options |= EOptionMemoryLeakMode;
                break;
            case 'o':
                binaryFileName = argv[1];
                if (argc > 0) {
                    argc--;
                    argv++;
                } else
                    Error("no <file> provided for -o");
                break;
            case 'q':
                Options |= EOptionDumpReflection;
                break;
            case 'r':
                Options |= EOptionRelaxedErrors;
                break;
            case 's':
                Options |= EOptionSuppressInfolog;
                break;
            case 't':
                #ifdef _WIN32
                    Options |= EOptionMultiThreaded;
                #endif
                break;
            case 'v':
                Options |= EOptionDumpVersions;
                break;
            case 'w':
                Options |= EOptionSuppressWarnings;
                break;
            case 'x':
                Options |= EOptionOutputHexadecimal;
                break;
            default:
                usage();
                break;
            }
        } else {
            std::string name(argv[0]);
            if (! SetConfigFile(name)) {
                Work[argc] = new glslang::TWorkItem(name);
                Worklist.add(Work[argc]);
            }
        }
    }

    // Make sure that -E is not specified alongside linking (which includes SPV generation)
    if ((Options & EOptionOutputPreprocessed) && (Options & EOptionLinkProgram))
        Error("can't use -E when linking is selected");

    // -o or -x makes no sense if there is no target binary
    if (binaryFileName && (Options & EOptionSpv) == 0)
        Error("no binary generation requested (e.g., -V)");

    if ((Options & EOptionFlattenUniformArrays) != 0 &&
        (Options & EOptionReadHlsl) == 0)
        Error("uniform array flattening only valid when compiling HLSL source.");
}