GLES 层
EGL加载器初始化
所有标准入口点均未修改地填充后,将实例化一个GLES LayerLoader。如果启用了调试层,LayerLoader 将扫描指定目录中的层,就像Vulkan 加载器一样。
如果启用了分层功能,加载器将搜索并枚举指定的图层列表。图层列表将由冒号分隔的文件名指定(请参阅下文的启用图层)。
图层将按照指定的顺序进行遍历,因此第一个图层将直接位于应用程序下方。对于每个图层,它将跟踪该图层的两个入口点: AndroidGLESLayer_Initialize
和AndroidGLESLayer_GetProcAddress
。
typedef void * (* PFNEGLGETNEXTLAYERPROCADDRESSPROC )(void *,const char *);
无效* AndroidGLESLayer_Initialize (无效* layer_id , PFNEGLGETNEXTLAYERPROCADDRESSPROC get_next_layer_proc_address ))
AndroidGLESLayer_Initialize
是一个新函数,它为要使用的层提供了一个标识符 (layer_id),以及一个可以调用来查找层下函数的入口点。入口点的使用方式如下:
const char * func = "eglFoo" ;
void * gpa = get_next_layer_proc_address ( layer_id,func ) ;
请注意,仅提供GLES2+ 入口点。如果某个层尝试进行独立的GLES 1.x 调用,它们将被路由到GLES2+ 库,这可能会导致行为不符合预期。应用对1.x 的调用不会受到影响。
AndroidGLESLayer_GetProcAddress 是专为此分层系统设计的一个新函数。它获取该层完成后应调用的链中下一个调用的地址。如果只有一个层,则对于大多数函数,next 将直接指向驱动程序。
void * AndroidGLESLayer_GetProcAddress ( const char * funcName , EGLFuncPointer next )
对于找到的每个层,GLES LayerLoader 都会调用 AndroidGLESLayer_Initialize
,然后遍历 libEGL 的函数列表,并针对所有已知函数调用 AndroidGLESLayer_GetProcAddress
。该层可以使用任何方式跟踪下一个地址。如果该层未拦截该函数,则 AndroidGLESLayer_GetProcAddress
必须返回与其传入的相同函数地址。然后,LayerLoader 将更新函数钩子列表,使其指向该层的入口点。
图层无需使用 AndroidGLESLayer_Initialize
或get_next_layer_proc_address 提供的信息执行任何操作,但提供这些信息可以让现有图层(如 GAPID 和 RenderDoc)更轻松地支持 Android。这样,图层就可以独立查找函数(即无需等待
AndroidGLESLayer_GetProcAddress`的调用)。如果图层查找函数调用,则必须确保使用 gen_next_layer_proc_address 而不是 eglGetProcAddress,否则将无法获得准确的答案。eglGetProcAddress 必须沿链向下传递到平台。
##放置图层
按照优先级顺序查找图层
1.根目录的系统位置
这需要 root 权限
bash adb root adb disable-verity adb重启 adb root adb shell setenforce 0 adb shell mkdir -p /数据/本地/调试/gles adb push <layer>.so /data/local/debug/gles/
-
Application’s base directory
Target application must be debuggable, or you must have root access:adb push libGLTrace.so /data/local/tmp adb shell run-as com.android.gl2jni cp /data/local/tmp/libGLTrace.so . adb shell run-as com.android.gl2jni ls | grep libGLTrace libGLTrace.so
-
External APK
Determine the ABI of your target application, then install an APK containing the layers you wish to load:adb install --abi armeabi-v7a layers.apk
-
In the target application’s APK
Enabling layers
Per application
Note these settings will persist across reboots:
# Enable layers
adb shell settings put global enable_gpu_debug_layers 1
# Specify target application
adb shell settings put global gpu_debug_app <package_name>
# Specify layer list (from top to bottom)
adb shell settings put global gpu_debug_layers_gles <layer1:layer2:layerN>
# Specify a package to search for layers
adb shell settings put global gpu_debug_layer_app <layer_package>
To disable the per-app layers:
adb shell settings delete global enable_gpu_debug_layers
adb shell settings delete global gpu_debug_app
adb shell settings delete global gpu_debug_layers_gles
adb shell settings delete global gpu_debug_layer_app
Globally
These will be cleared on reboot:
# This will attempt to load layers for all applications, including native executables
adb shell setprop debug.gles.layers <layer1:layer2:layerN>
Creating a layer
Layers must expose the following two functions described above:
AndroidGLESLayer_Initialize
AndroidGLESLayer_GetProcAddress
For a simple layer that just wants to intercept a handful of functions, a passively initialized layer is the way to go. It can simply wait for the EGL Loader to initialize the function it cares about. See below for an example of creating a passive layer.
For more formalized layers that need to fully initialize up front, or layers that needs to look up extensions not known to the EGL loader, active layer initialization is the way to go. The layer can utilize get_next_layer_proc_address provided by AndroidGLESLayer_Initialize
to look up a function at any time. The layer must still respond to AndroidGLESLayer_GetProcAddress
requests from the loader so the platform knows where to route calls. See below for an example of creating an active layer.
Example Passive Layer Initialization
namespace {
std::unordered_map<std::string, EGLFuncPointer> funcMap;
EGLAPI EGLBoolean EGLAPIENTRY glesLayer_eglChooseConfig (
EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size,
EGLint *num_config) {
EGLFuncPointer entry = funcMap["eglChooseConfig"];
typedef EGLBoolean (*PFNEGLCHOOSECONFIGPROC)(
EGLDisplay, const EGLint*, EGLConfig*, EGLint, EGLint*);
PFNEGLCHOOSECONFIGPROC next = reinterpret_cast<PFNEGLCHOOSECONFIGPROC>(entry);
return next(dpy, attrib_list, configs, config_size, num_config);
}
EGLAPI EGLFuncPointer EGLAPIENTRY eglGPA(const char* funcName) {
#define GETPROCADDR(func) if(!strcmp(funcName, #func)) { \
return (EGLFuncPointer)glesLayer_##func; }
GETPROCADDR(eglChooseConfig);
// Don't return anything for unrecognized functions
return nullptr;
}
EGLAPI void EGLAPIENTRY glesLayer_InitializeLayer(
void* layer_id, PFNEGLGETNEXTLAYERPROCADDRESSPROC get_next_layer_proc_address) {
// This function is purposefully empty, since this layer does not proactively
// look up any entrypoints
}
EGLAPI EGLFuncPointer EGLAPIENTRY glesLayer_GetLayerProcAddress(
const char* funcName, EGLFuncPointer next) {
EGLFuncPointer entry = eglGPA(funcName);
if (entry != nullptr) {
funcMap[std::string(funcName)] = next;
return entry;
}
return next;
}
} // namespace
extern "C" {
__attribute((visibility("default"))) EGLAPI void AndroidGLESLayer_Initialize(
void* layer_id, PFNEGLGETNEXTLAYERPROCADDRESSPROC get_next_layer_proc_address) {
return (void)glesLayer_InitializeLayer(layer_id, get_next_layer_proc_address);
}
__attribute((visibility("default"))) EGLAPI void* AndroidGLESLayer_GetProcAddres(
const char *funcName, EGLFuncPointer next) {
return (void*)glesLayer_GetLayerProcAddress(funcName, next);
}
}
Example Active Layer Initialization
namespace {
std::unordered_map<std::string, EGLFuncPointer> funcMap;
EGLAPI EGLBoolean EGLAPIENTRY glesLayer_eglChooseConfig (
EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size,
EGLint *num_config) {
EGLFuncPointer entry = funcMap["eglChooseConfig"];
typedef EGLBoolean (*PFNEGLCHOOSECONFIGPROC)(
EGLDisplay, const EGLint*, EGLConfig*, EGLint, EGLint*);
PFNEGLCHOOSECONFIGPROC next = reinterpret_cast<PFNEGLCHOOSECONFIGPROC>(entry);
j
return next(dpy, attrib_list, configs, config_size, num_config);
}
EGLAPI EGLFuncPointer EGLAPIENTRY eglGPA(const char* funcName) {
#define GETPROCADDR(func) if(!strcmp(funcName, #func)) { \
return (EGLFuncPointer)glesLayer_##func; }
GETPROCADDR(eglChooseConfig);
// Don't return anything for unrecognized functions
return nullptr;
}
EGLAPI void EGLAPIENTRY glesLayer_InitializeLayer(
void* layer_id, PFNEGLGETNEXTLAYERPROCADDRESSPROC get_next_layer_proc_address) {
// Note: This is where the layer would populate its function map with all the
// functions it cares about
const char* func = “eglChooseConfig”;
funcMap[func] = get_next_layer_proc_address(layer_id, func);
}
EGLAPI EGLFuncPointer EGLAPIENTRY glesLayer_GetLayerProcAddress(
const char* funcName, EGLFuncPointer next) {
EGLFuncPointer entry = eglGPA(funcName);
if (entry != nullptr) {
return entry;
}
return next;
}
} // namespace
extern "C" {
__attribute((visibility("default"))) EGLAPI void AndroidGLESLayer_Initialize(
void* layer_id, PFNEGLGETNEXTLAYERPROCADDRESSPROC get_next_layer_proc_address) {
return (void)glesLayer_InitializeLayer(layer_id, get_next_layer_proc_address);
}
__attribute((visibility("default"))) EGLAPI void* AndroidGLESLayer_GetProcAddres(
const char *funcName, EGLFuncPointer next) {
return (void*)glesLayer_GetLayerProcAddress(funcName, next);
}
}
Caveats
Only supports GLES 2.0+.
When layering is enabled, GLES 1.x exclusive functions will continue to route to GLES 1.x drivers. But functions shared with GLES 2.0+ (like glGetString) will be routed to 2.0+ drivers, which can cause confusion.
FAQ
- Who can use layers?
- GLES Layers can be loaded by any debuggable application, or for any application if you have root access
- How do we know if layers are working on a device?
- This feature is backed by Android CTS, so you can run
atest CtsGpuToolsHostTestCases
- This feature is backed by Android CTS, so you can run
- How does a app determine if this feature is supported?
- There are two ways. First you can check against the version of Android.
# Q is the first that will support this, so look for `Q` or 10 for release adb shell getprop ro.build.version.sdk # Or look for the SDK version, which should be 29 for Q adb shell getprop ro.build.version.sdk
- Secondly, if you want to determine from an application that can’t call out to ADB for this, you can check for the EGL_ANDROID_GLES_layers. It simply indicates support of this layering system:
std::string display_extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); if (display_extensions.find("EGL_ANDROID_GLES_layers") != std::string::npos) { // Layers are supported! }
- There are two ways. First you can check against the version of Android.
这里写自定义目录标题
欢迎使用Markdown编辑器
你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。
新的改变
我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:
- 全新的界面设计 ,将会带来全新的写作体验;
- 在创作中心设置你喜爱的代码高亮样式,Markdown 将代码片显示选择的高亮样式 进行展示;
- 增加了 图片拖拽 功能,你可以将本地的图片直接拖拽到编辑区域直接展示;
- 全新的 KaTeX数学公式 语法;
- 增加了支持甘特图的mermaid语法1 功能;
- 增加了 多屏幕编辑 Markdown文章功能;
- 增加了 焦点写作模式、预览模式、简洁写作模式、左右区域同步滚轮设置 等功能,功能按钮位于编辑区域与预览区域中间;
- 增加了 检查列表 功能。
功能快捷键
撤销:Ctrl/Command + Z
重做:Ctrl/Command + Y
加粗:Ctrl/Command + B
斜体:Ctrl/Command + I
标题:Ctrl/Command + Shift + H
无序列表:Ctrl/Command + Shift + U
有序列表:Ctrl/Command + Shift + O
检查列表:Ctrl/Command + Shift + C
插入代码:Ctrl/Command + Shift + K
插入链接:Ctrl/Command + Shift + L
插入图片:Ctrl/Command + Shift + G
查找:Ctrl/Command + F
替换:Ctrl/Command + G
合理的创建标题,有助于目录的生成
直接输入1次#,并按下space后,将生成1级标题。
输入2次#,并按下space后,将生成2级标题。
以此类推,我们支持6级标题。有助于使用TOC
语法后生成一个完美的目录。
如何改变文本的样式
强调文本 强调文本
加粗文本 加粗文本
标记文本
删除文本
引用文本
H2O is是液体。
210 运算结果是 1024.
插入链接与图片
链接: link.
图片:
带尺寸的图片:
居中的图片:
居中并且带尺寸的图片:
当然,我们为了让用户更加便捷,我们增加了图片拖拽功能。
如何插入一段漂亮的代码片
去博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 代码片
.
// An highlighted block
var foo = 'bar';
生成一个适合你的列表
- 项目
- 项目
- 项目
- 项目
- 项目1
- 项目2
- 项目3
- 计划任务
- 完成任务
创建一个表格
一个简单的表格是这么创建的:
项目 | Value |
---|---|
电脑 | $1600 |
手机 | $12 |
导管 | $1 |
设定内容居中、居左、居右
使用:---------:
居中
使用:----------
居左
使用----------:
居右
第一列 | 第二列 | 第三列 |
---|---|---|
第一列文本居中 | 第二列文本居右 | 第三列文本居左 |
SmartyPants
SmartyPants将ASCII标点字符转换为“智能”印刷标点HTML实体。例如:
TYPE | ASCII | HTML |
---|---|---|
Single backticks | 'Isn't this fun?' | ‘Isn’t this fun?’ |
Quotes | "Isn't this fun?" | “Isn’t this fun?” |
Dashes | -- is en-dash, --- is em-dash | – is en-dash, — is em-dash |
创建一个自定义列表
-
Markdown
- Text-to- HTML conversion tool Authors
- John
- Luke
如何创建一个注脚
一个具有注脚的文本。2
注释也是必不可少的
Markdown将文本转换为 HTML。
KaTeX数学公式
您可以使用渲染LaTeX数学表达式 KaTeX:
Gamma公式展示 Γ ( n ) = ( n − 1 ) ! ∀ n ∈ N \Gamma(n) = (n-1)!\quad\forall n\in\mathbb N Γ(n)=(n−1)!∀n∈N 是通过欧拉积分
Γ ( z ) = ∫ 0 ∞ t z − 1 e − t d t . \Gamma ( z ) = \int _0^ \infty t^ { z-1 } e^ { -t } dt \, . Γ(z)=∫0∞tz−1e−tdt.
你可以找到更多关于的信息 LaTeX 数学表达式[here][1].
新的甘特图功能,丰富你的文章
“美人鱼
甘特图
日期格式 YYYY-MM-DD
标题 为 Mermaid 添加 GANTT 图表功能
section 现有任务
已完成 :done, des1, 2014-01-06,2014-01-08
进行中 :active, des2, 2014-01-09, 3d
计划一 : des3, after des2, 5d
计划二 : des4, after des3, 5d
- 关于 **甘特图** 语法,参考 [这儿][2],
## UML 图表
可以使用UML图表进行渲染。 [Mermaid](https://mermaidjs.github.io/). 例如下面产生的一个序列图:
“美人鱼
序列图
张三 ->> 李四: 你好!李四, 最近怎么样?
李四-->>王五: 你最近怎么样,王五?
李四--x 张三: 我很好,谢谢!
李四-x 王五: 我很好,谢谢!
Note right of 王五: 李四想了很长时间, 文字太长了<br/>不适合放在一行.
李四-->>张三: 打量着王五...
张三->>王五: 很好... 王五, 你怎么样?
这将产生一个流程图。 :
“美人鱼
图LR
A[长方形] – 链接 --> B((圆))
A --> C(圆角长方形)
B --> D{菱形}
C–>D
- 关于 **Mermaid** 语法,参考 [这儿][3],
## FLowchart流程图
我们依旧会支持flowchart的流程图:
“美人鱼
流程图
st=>start: 开始
e=>end: 结束
op=>operation: 我的操作
cond=>condition: 确认?
st->op->cond
cond(是)->e
cond(无)->op
- 关于 Flowchart流程图 语法,参考 [这儿][4].
导出与导入
导出
如果你想尝试使用此编辑器, 你可以在此篇文章任意编辑。当你完成了一篇文章的写作, 在上方工具栏找到 文章导出 ,生成一个.md文件或者.html文件进行本地保存。
导入
如果你想加载一篇你写过的.md文件,在上方工具栏可以选择导入功能进行对应扩展名的文件导入,
继续你的创作。
[ 1 ]: http://meta.math.stackexchange.com/questions/5020/mathjax-basic-tutorial-and-quick-reference
[ 2 ]: https: //mermaidjs.github.io/
[ 3 ]: https: //mermaidjs.github.io/
[ 4 ]: http: //adrai.github.io/flowchart.js/
注脚的解释 ↩︎