HLSL Cross Compiler

This library compiles High Level Shading Language (HLSL) shader source code into a high-level intermediate representation, performs device-independent optimizations, and produces OpenGL Shading Language (GLSL) compatible source code. The library is largely based on the GLSL compiler from Mesa. The frontend has been heavily rewritten to parse HLSL and generate Mesa IR from the HLSL Abstract Syntax Tree (AST). The library leverages Mesa's IR optimization to simplify the code and finally generates GLSL source code from the Mesa IR. The GLSL generation is based on the work in glsl-optimizer.

In addition to producing GLSL code, the compiler packs global uniforms in to an array for easy and efficient setting, provides a reflection mechanism to inform high level code which uniforms are required, and provides mapping information so that high level code may bind resources by index rather than by name at runtime.

UnrealBuildTool does not detect changes to external libraries, such as the HLSLCC. When you rebuild the HLSLCC library, add a space to OpenGLShaders.cpp to force the module to re-link.

The main library entry point is HLSLCrossCompile. This function performs all steps needed to generate GLSL code from the source HLSL with the requested options. A summary of each stage follows:

Operation

Description

Preprocessing

The code is run through a C-like preprocessor. This stage is optional and may be omitted by using the NoPreprocess flag. Unreal performs preprocessing using MCPP before compilation and therefore skips this step.

Parsing

The HLSL source is parsed in to an abstract syntax tree. This is done in the function _mesa_hlsl_parse. The lexer and parser are generated by flex and bison respectively. See the section on parsing for more information.

Compilation

The AST is compiled in to Mesa intermediate representation. This process happens in the function _mesa_ast_to_hir. During this stage, the compiler performs functions such as implicit conversions, function overload resolution, generating instructions for intrinsics, and so on. A GLSL main entry point is generated. See GenerateGlslMain. This stage will add global declarations for input and output variables to the IR, compute the inputs for the HLSL entry point, call the HLSL entry point, and write outputs to the global output variables.

Optimization

Several optimization passes are performed on the IR including function inlining, dead code elimination, constant propagation, elimination of common subexpressions, and so on. See OptimizeIR and especially do_optimization_pass for details.

Uniform packing

Global uniforms are packed in to arrays with mapping information retained so the engine may bind parameters to the relevant portion of the uniform array. See PackUniforms for details.

Final optimization

After uniforms have been packed, a second round of optimizations is run on the IR to simplify the code generated when packing uniforms.

Generate GLSL

Finally the optimized IR is converted to GLSL source code. The conversion from IR to GLSL is relatively straight-forward. In addition to producing definitions of all structs and uniform buffers and the source itself, a mapping table is written out in comments at the top of the file. This mapping table is parsed by Unreal to allow the binding of parameters. See GenerateGlsl and especially the ir_gen_glsl_visitor class for details.

Parsing

The HLSL parser is built in two parts: the lexer and the parser. The lexer tokenizes the HLSL input by matching regular expressions to corresponding tokens. The source file is hlsl_lexer.ll and is processed by flex to produce C code. Each line begins with a regular expression followed by a statement written in C code. When the regular expression is matched, the corresponding C code is executed. State is stored in a number of global variables prefixed with "yy".

The parser matches rules to the tokenized input in order to interpret the grammar of the language and builds an AST. The source file is hlsl_parser.yy and is processed by bison to produce C code. Fully explaining the syntax used by bison is outside the scope of this document but looking at the HLSL parser should shed some light on the basics. In general, you define a rule as matching some sequence of tokens evaluated recursively. When a rule has been matched, some corresponding C code is executed allowing you to build your AST. The syntax within the C code block is as follows:

$$ = the result of parsing this rule, usually a node in the abstract syntax tree $1, $2, etc. = the outputs of the sub-rules matched by the current rule

When making changes to the lexer or parser, you must regenerate the C code using flex and bison. The GenerateParsers batch file handles this for you but you must setup the directories based on where flex and bison are installed on your system. The README file contains information on the versions I used and where binaries can be downloaded for Windows.

Compilation

During compilation, the AST is traversed and used to generate IR instructions. One important concept to grasp is that IR is a very low level sequence of operations. As such, it does not perform implicit conversions or anything of that nature: everything must be done explicitly.

Some common functions of interest:

apply_type_conversion - This function converts a value of one type to another if possible. Implicit versus explicit conversions are controlled via a parameter.

arithmetic_result_type, et. al. - A set of functions that determine the result type of applying an operation to input values.

validate_assignment - Determines if an rvalue can be assigned to an lvalue of a particular type. Allowed implicit conversions will be applied if necessary.

do_assignment - Assigns an rvalue to an lvalue if possible using validate_assignment.

ast_expression::hir - Converts an expression node in the AST to a set of IR instructions.

process_initializer - Applies an initializer expression to a variable.

ast_struct_specifier::hir - Builds an aggregate type to represent a declared structure.

ast_cbuffer_declaration::hir - Builds a struct for the constant buffer layout and stores it as a uniform block.

process_mul - Special code to handle the HLSL intrinsic mul.

match_function_by_name - Looks up a function signature based on name and the list of input parameters.

rank_parameter_lists - Compares two parameter lists and assigns a numerical rank indicating how closely the lists match. This is a helper function used to perform overload resolution: the signature with the lowest rank wins and a function call is declared ambiguous if any signature has the same rank as the lowest ranking signature. A rank of zero indicates an exact match.

gen_texture_op - Handles method calls for builtin HLSL texture and sampler objects.

_mesa_glsl_initialize_functions - Generates builtin functions for HLSL intrinsics. Most functions (e.g. sin, cos) generate IR code to perform the operation but some (e.g. transpose, determinant) leave in function calls deferring the operation to the driver's GLSL compiler.

Extending the Compiler

Here are some tips on implementing some types of features:

New Expressions

Add an entry to the ir_expression_operation enum.
In the ir_expression constructor handle your new expression to setup the typed result of the expression based on the types of input operands.
If possible, add a handler to ir_expression::constant_expression_value to allow constant expressions to be evaluated at compile time.
Add a handler to ir_validate::visit_leave(ir_expression *ir) to validate the correctness of the expression.
Add an entry to the GLSLExpressionTable to map your expression to a GLSL expression.
Modify the lexer to recognize the token(s) for your expression, if applicable.
Modify the parser to recognize the token and create an appropriate ast_expression node, if applicable.

Intrinsics

Add a builtin function definition to _mesa_glsl_initialize_functions.
In most cases an intrinsic will map directly to a single expression. If that is the case, simply add a new ir_expression and use make_intrinsic_genType to generate the intrinsic function.

Types

Add a glsl_type to represent your type within the IR. You can add this to _mesa_glsl_initialize_types or add it to one of the builtin type tables, e.g. glsl_type::builtin_core_types. For templated types see glsl_type::get_sampler_instance as an example.
Modify the lexer to recognize the necessary token and the parser to match your token. See Texture2DArray as an example.
Modify the parser to recognize the token and create the necessary type specifier. texture_type_specifier_nonarray is a good example.
Modify ast_type_specifier::hir to perform any processing needed to create user-defined types. See the handling for structures as an example.
Modify ast_type_specifier::glsl_type to return an appropriate glsl_type.
If the type contains methods, modify _mesa_ast_field_selection_to_hir to handle them. See gen_texture_op as an example.

Attributes, flags, and qualifiers

Add the attributes / flags / qualifiers to any IR and/or AST nodes where you will need them.
Modify the lexer to recognize the necessary tokens.
Modify the parser to add the grammatical rules as needed. E.g. if you were to add support for the [loop] attribute you'd modify the iteration_statement rule to accept an optional attribute preceeding it. Something like this: change iteration_statement to base_iteration_statement and add

iteration_statement:

iteration_attr base_iteration_statement
{
// result is the iteration statement
$$ = $2;
// apply attribute
$$->attr = $1;
}
base_iteration_statement
{
// pass thru if no attribute
$$ = $1;
}

Finally, make modifications anywhere in the compiler where you need to know about the attribute.

来自 <https://docs.unrealengine.com/en-us/Programming/Rendering/ShaderDevelopment/HLSLCrossCompiler>

(转) Unreal的HLSL交叉编译-UEAPI的更多相关文章

  1. Shader预处理宏、内置状态变量、多版本编译等

    预定义shader预处理宏: Target platform: SHADER_API_OPENGL - desktop OpenGL SHADER_API_D3D9 - Direct3D SHADER ...

  2. (转) Unreal Engine 4 Custom Shaders Tutorial

    说明: 1.这里的Custom Shaders 为且仅为 Custom Node的使用和USF的包含.并非全局Shader和Material Shader. 2.原文来源:https://www.ra ...

  3. (原)Unreal渲染模块 管线 - 着色器(1)

    @author: 白袍小道 转载悄悄说明下 随缘查看,施主开心就好 说明: 本篇继续Unreal搬山部分的渲染模块的Shader部分, 主要牵扯模块RenderCore, ShaderCore, RH ...

  4. (转)Unreal Shader模块(四): 着色器编译

    本文为(转):Unreal 调试着色器编译过程     调试着色器编译过程 Rolando Caloca 在 April 19, 2016 | 学习编程 Share on Facebook  Shar ...

  5. Unreal如何进行材质优化?

    Hello,大家好,今天给大家带来实用的材质优化,我是木偶心没.优化在每个游戏项目里面都会涉及到,是一种为了达成相同目标,寻求并采用消耗更少资源的办法.一般会在CPU,GPU,网络和内存方便进行优化. ...

  6. Linux主机上使用交叉编译移植u-boot到树莓派

    0环境 Linux主机OS:Ubuntu14.04 64位,运行在wmware workstation 10虚拟机 树莓派版本:raspberry pi 2 B型. 树莓派OS: Debian Jes ...

  7. Ubuntu 16.04 安装 arm-linux-gcc 嵌入式交叉编译环境 问题汇总

    闲扯: 实习了将近半年一直在做硬件以及底层的驱动,最近要找工作了发现了对linux普遍要求很高,而且工作岗位也非常多,所以最近一些时间在时不时地接触linux. 正文:(我一时兴起开始写博客,准备不充 ...

  8. 《Note --- Unreal --- MemPro (CONTINUE... ...)》

    Mem pro 是一个主要集成内存泄露检测的工具,其具有自身的源码和GUI,在GUI中利用"Launch" button进行加载自己待检测的application,目前支持的平台为 ...

  9. Linux 14.04lts 环境下搭建交叉编译环境arm-linux-gcc-4.5.1

    交叉编译工具链是为了编译.链接.处理和调试跨平台体系结构的程序代码,在该环境下编译出嵌入式Linux系统所需要的操作系统.应用程序等,然后再上传到目标板上. 首 先要明确gcc 和arm-linux- ...

随机推荐

  1. Linux开发常见问题:GCC:链接器输入文件未使用,因为链接尚未完成

    问:我在Linux中运行一个make文件去编译C语言代码,然后得到了如下的错误信息: gcc  -Wall  -fPIC  -DSOLARIS  -DXP_UNIX  -DMCC_HTTPD  -D_ ...

  2. iterm2配置项

    1. 启动终端Terminal2. 进入当前用户的home目录    输入cd ~3. 创建.bash_profile    输入touch .bash_profile 在导入并应用完颜色方案之后,通 ...

  3. MyBatis简单了解

    MyBatis 是什么? MyBatis 是一个简化和实现了 Java 数据持久化层(persistence layer)的开源框架,它抽象了大量的 JDBC 冗余代 码,并提供了一个简单易用的 AP ...

  4. A Multigrid Tutorial中涉及到的难点词汇

    Multigrid Tutorial中涉及的词汇: Elliptic PDEs 椭圆型偏微分方程 Lawrence Livermore National Laboratory 劳伦斯利福摩尔国家实验室 ...

  5. Linux中的/etc/nologin问题

    /etc/nologin 文件给系统管理员提供了在 Linux 系统维护期间禁止用户登陆的方式. 如果系统中存在 /etc/nologin 文件那么普通用户登陆就会失败. 这是一种提高安全性和防止数据 ...

  6. Eclipse 修改默认工作空间

    第一次启动Eclipse时会弹出对话框,让你进行Workspace Launcher,也就是设置Eclipse的项目存放路径.但是,当你勾选“Use this as the default and d ...

  7. Mysql url参数浅析

    驱动包用的是mysql-connector-java-8.0.11.jar 新版的驱动类改成了com.mysql.cj.jdbc.Driver //北京时间东八区 serverTimezone=GMT ...

  8. 11-UITableView

    UITableView 掌握 设置UITableView的dataSource.delegate UITableView多组数据和单组数据的展示 UITableViewCell的常见属性 UITabl ...

  9. gdb几个操作

    如果进程转为守护进程,可设置如下跟进子进程 set follow-fork-mode child 输出变量/函数/返回值有print, call, display,自行选择 对于打印value has ...

  10. ES6笔记04-class的基本语法

    JavaScript 语言中,生成实例对象的传统方法是通过构造函数. ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板.通过class关键字,可以定义类. clas ...