(转) Unreal的HLSL交叉编译-UEAPI
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的更多相关文章
- Shader预处理宏、内置状态变量、多版本编译等
预定义shader预处理宏: Target platform: SHADER_API_OPENGL - desktop OpenGL SHADER_API_D3D9 - Direct3D SHADER ...
- (转) Unreal Engine 4 Custom Shaders Tutorial
说明: 1.这里的Custom Shaders 为且仅为 Custom Node的使用和USF的包含.并非全局Shader和Material Shader. 2.原文来源:https://www.ra ...
- (原)Unreal渲染模块 管线 - 着色器(1)
@author: 白袍小道 转载悄悄说明下 随缘查看,施主开心就好 说明: 本篇继续Unreal搬山部分的渲染模块的Shader部分, 主要牵扯模块RenderCore, ShaderCore, RH ...
- (转)Unreal Shader模块(四): 着色器编译
本文为(转):Unreal 调试着色器编译过程 调试着色器编译过程 Rolando Caloca 在 April 19, 2016 | 学习编程 Share on Facebook Shar ...
- Unreal如何进行材质优化?
Hello,大家好,今天给大家带来实用的材质优化,我是木偶心没.优化在每个游戏项目里面都会涉及到,是一种为了达成相同目标,寻求并采用消耗更少资源的办法.一般会在CPU,GPU,网络和内存方便进行优化. ...
- Linux主机上使用交叉编译移植u-boot到树莓派
0环境 Linux主机OS:Ubuntu14.04 64位,运行在wmware workstation 10虚拟机 树莓派版本:raspberry pi 2 B型. 树莓派OS: Debian Jes ...
- Ubuntu 16.04 安装 arm-linux-gcc 嵌入式交叉编译环境 问题汇总
闲扯: 实习了将近半年一直在做硬件以及底层的驱动,最近要找工作了发现了对linux普遍要求很高,而且工作岗位也非常多,所以最近一些时间在时不时地接触linux. 正文:(我一时兴起开始写博客,准备不充 ...
- 《Note --- Unreal --- MemPro (CONTINUE... ...)》
Mem pro 是一个主要集成内存泄露检测的工具,其具有自身的源码和GUI,在GUI中利用"Launch" button进行加载自己待检测的application,目前支持的平台为 ...
- Linux 14.04lts 环境下搭建交叉编译环境arm-linux-gcc-4.5.1
交叉编译工具链是为了编译.链接.处理和调试跨平台体系结构的程序代码,在该环境下编译出嵌入式Linux系统所需要的操作系统.应用程序等,然后再上传到目标板上. 首 先要明确gcc 和arm-linux- ...
随机推荐
- 导航栏上的item的位置设置
/** leftItem */ UIButton *leftbtn = [[UIButton alloc]initWithFrame:CGRectMake(, , , )]; [leftbtn set ...
- 【转】Android BroadcastReceiver介绍
本文主要介绍BroadcastReceiver的概念.使用.生命周期.安全性.分类.特殊的BroadcastReceiver(本地.粘性.有序.粘性有序广播).示例代码见BroadcastReceiv ...
- Matlab 绘图实例
概要 每次用 Matlab 绘图都要搜一堆资料设置一些参数,本次将绘图中的一些参数设置实例展示在这里,以备不时之需.暂包括折线图,面积图. 折线图实例 下图是效果图: 图 1:折线图效果图 ...
- ceph-对象存储
ceph对象存储 作为文件系统的磁盘,操作系统不能直接访问对象存储.相反,它只能通过应用程序级别的API访问.ceph是一种分布式对象存储系统,通过ceph对象网关提供对象存储接口,也称为RADOS网 ...
- idea中不重启服务器更改代码(使用jrebel)
http://139.199.89.239:1008/88414687-3b91-4286-89ba-2dc813b107ce 第一步 第二步:下载jrebel 第三步(这里有些有有些没有) 下载完后 ...
- Vscode插件--微信小程序格式化以及高亮组件wxml-vscode
wxml-vscode wxml-vscode 仓库 提问题 安装 通过 F1 或者 CMD + Shift + P 输入 install. 选择: Install Extension. 特性 格式化 ...
- 浅谈mysql权限
一. 背景: “去IOE”的本质是“分布式+开源”架构替代“集中式+封闭”架构,变成彻底的云计算服务模式.去“IE”易,并且应该去,关键确实能省钱,而且运维难度不大,替代技术产品成熟.而去O ...
- Java对象容器总结
泛型容器类 容器类型: ArrayList 元素类型: 有排序 String:里面存放的是对象的管理者,而不是具体的对象,所以string类型有null值 集合容器 容器类型 Set 元素类型 唯一性 ...
- mysql中列属性
mysql列属性包括:NULL .default.comment.primary key.unique key 一.NULL定义方式:NULL(默认) NOT NULL 空属性有2个值,mysql数据 ...
- Apache Maven(二):构建生命周期
Maven 约定的目录结构 我要遵循Maven已经约定好的目录结构,才能让maven在自动构建过程中找到对应的资源进行构建处理.以下是maven约定的目录结构: 项目名称 |-- pom.xml :M ...