(转) 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- ...
随机推荐
- 【BZOJ3622】已经没有什么好害怕的了(动态规划+广义容斥)
点此看题面 大致题意: 有\(n\)个糖果和\(n\)个药片,各有自己的能量.将其两两配对,求糖果比药片能量大的组数恰好比药片比糖果能量大的组数多\(k\)组的方案数. 什么是广义容斥(二项式反演) ...
- arraylist,list ,数组区别
https://www.cnblogs.com/a164266729/p/4561651.html
- 怎么让Sublime Text不自动打开最近的文件/项目
"hot_exit": false,"remember_open_files": false,
- Java-笔记1
/* 对第一个java程序进行总结 1. java程序编写-编译-运行的过程 编写:我们将编写的java代码保存在以".java"结尾的源文件中 编译:使用javac.exe命令编 ...
- 第38章 I2S—音频播放与录音输入—零死角玩转STM32-F429系列
第38章 I2S—音频播放与录音输入 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/ ...
- Spring 中IOC(控制反转)&& 通过SET方式为属性注入值 && Spring表达式
### 1. Spring IoC IoC:Inversion of control:控制反转:在传统开发模式下,对象的创建过程和管理过程都是由开发者通过Java程序来实现的,操作权在开发者的Java ...
- SpringMVC-实现PUT请求上传文件(转)
因为在图片上传的时候使用的是二进制的方式上传,所以使用隐藏域进行方法转换方式失效,转方法: https://www.cnblogs.com/morethink/p/6378015.html 可是后来我 ...
- Linux文件服务器实战(虚拟用户)
vsftpd基于系统用户访问ftp服务器,系统用户越多越不利于管理,不利于系统安全,这样就以vsftp虚拟防护的方式来解决. 虚拟用户没有实际的真实系统用户,,而是通过映射到其中一个真实用户以及设置相 ...
- Centos7上docker的安装和基本使用
Centos7上Docker的相关操作 Docker的安装 1.检查内核版本 docker使用linux的内核必须是3.10以上,首先需要 # uname -r 2.使用yum安装docker # y ...
- 正则(re 模块)
就其本质而言,正则表达式(或 RE)是一种小型的.高度专业化的编程语言,(在Python中)它内嵌在Python中,并通过 re 模块实现.正则表达式模式被编译成一系列的字节码,然后由用 C 编写的匹 ...