Skip to content

Commit 1d8d77c

Browse files
committed
first
0 parents  commit 1d8d77c

File tree

183 files changed

+15368
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

183 files changed

+15368
-0
lines changed

.gitattributes

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Set the default behavior, in case people don't have core.autocrlf set.
2+
* text=auto
3+
4+
*.glsl text eol=lf
5+
*.wgsl text eol=lf
6+
*.vs text eol=lf
7+
*.fs text eol=lf
8+
*.vert text eol=lf
9+
*.frag text eol=lf

.github/workflows/webpack.yml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
name: Webpack
2+
3+
on:
4+
push:
5+
branches: [ "main" ]
6+
pull_request:
7+
branches: [ "main" ]
8+
9+
jobs:
10+
build:
11+
runs-on: ubuntu-latest
12+
13+
strategy:
14+
matrix:
15+
node-version: [20.x]
16+
17+
steps:
18+
- uses: actions/checkout@v4
19+
20+
- name: Cache Node.js modules
21+
uses: actions/cache@v4
22+
with:
23+
path: node_modules
24+
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
25+
restore-keys: |
26+
${{ runner.os }}-node-
27+
28+
- name: Use Node.js ${{ matrix.node-version }}
29+
uses: actions/setup-node@v4
30+
with:
31+
node-version: ${{ matrix.node-version }}
32+
33+
- name: Build
34+
run: |
35+
npm install
36+
npx webpack
37+
38+
- name: Archive Artifact
39+
uses: actions/upload-artifact@v4
40+
with:
41+
name: GL2GPU-Chrome-Extension
42+
path: extension

.gitignore

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
node_modules/
2+
/test-results/
3+
/playwright-report/
4+
/playwright/.cache/
5+
*.har
6+
*.zst
7+
*.zstd
8+
.idea
9+
.vscode
10+
*.error.txt
11+
.DS_Store
12+
output
13+
/test-results/
14+
/playwright-report/
15+
/playwright/.cache/
16+
/test-results/
17+
/playwright-report/
18+
/playwright/.cache/
19+
traces
20+
/dist
21+
/examples/resources/
22+
extension/webpack/
23+
package-lock.json
24+
yarn.lock
25+
*.zip

.hintrc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"extends": [
3+
"development"
4+
],
5+
"hints": {
6+
"typescript-config/strict": "off"
7+
}
8+
}

README.md

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
# GL2GPU
2+
3+
> 如何使用静态的GL2GPU?
4+
5+
Webpack编译。指令 `npm i; npx webpack w`,根据`webpack.config.js`中的配置,静态的GL2GPU将在`dist/`中生成最终代码。`dist/release`, `dist/development`, `dist/release-minimized` 里面的 `gl2gpu.js` 都可以被使用。
6+
7+
翻译shader代码,翻译样例:`src/components/shaders/shaders_info.json`
8+
- 翻译辅助脚本:`src/components/shaders/glsl_to_bindings.py`
9+
- uniform 需要被特殊翻译!(TBW)
10+
11+
```typescript
12+
export function ShaderInfo2String(shaderInfo: ShaderInfoType): string {
13+
let res = "";
14+
let offset = 0;
15+
if (shaderInfo.uniforms.length > 0) {
16+
res += "struct HydUniformObject {\n";
17+
for (const uniform of shaderInfo.uniforms) {
18+
res += ` ${uniform.name}: ${uniform.wgsl_type},\n`;
19+
}
20+
res += "};\n\n";
21+
res += "@binding(0) @group(0) var<uniform> _hyd_uniforms_ : HydUniformObject;\n\n";
22+
offset = 1;
23+
}
24+
for (let i = 0; i < shaderInfo.samplers.length; i++) {
25+
const sampler = shaderInfo.samplers[i];
26+
res += `@binding(${i * 2 + offset + 0}) @group(0) var ${sampler.name}S: ${sampler.wgsl_sampler_type};\n`;
27+
res += `@binding(${i * 2 + offset + 1}) @group(0) var ${sampler.name}T: ${sampler.wgsl_texture_type};\n`;
28+
}
29+
return res;
30+
}
31+
```
32+
33+
34+
35+
修改WebGL应用。需要进行5处修改:
36+
1. 引用上一步中得到的 `gl2gpu.js` 文件
37+
2.`getContext("webgl", arg0?)` 修改为 `GL2GPU.getContext(canvas, <shader_json_url>, arg0?, arg1?)`
38+
- `this._gl = await GL2GPU.hydGetContext(this.element, "../shaders_info.json", ["webgl", { preserveDrawingBuffer: true }], [1<<18, 200]);`
39+
3. 将同步函数修改为异步函数调用 `async`-`await`
40+
4. 将渲染函数 `render()` (通常被 `requestAnimationFrame` 所调用)修改为 `GL2GPU.beginFrame(); render(); GL2GPU.endFrame();`
41+
42+
---
43+
44+
以下是动态GL2GPU文档。
45+
46+
Build Status: [![Build Status](https://github.com/yudshj/GL2GPU/workflows/Webpack/badge.svg)](https://github.com/yudshj/GL2GPU/actions)
47+
48+
# Evaluation 方法
49+
50+
Webpack编译指令 `npm i; npx webpack w`
51+
52+
用Webpack编译完成后,将得到一个 hydWrapper.js 文件。只需要把这个文件以某种合适的方法注入到页面中就能加载GL2GPU。
53+
54+
加载完毕后为了驱动 GL2GPU 执行,还需要调用 `HYD.hydInstrument` 来修改 `canvas``getContext` 方法。比如我们可以添加以下代码(见 `/extension/inject.js`):
55+
56+
```javascript
57+
const _GL2GPU_CONFIG = {
58+
cmbMode: "cmb",
59+
replayDelay: 5000,
60+
uniformBatchSize: 262144, // 256KB
61+
};
62+
63+
const proxy = new Proxy(window.requestAnimationFrame, {
64+
apply: function (target, thisArg, argumentsList) {
65+
const func = argumentsList[0];
66+
const funcNew = function (time) {
67+
HYD.runFrameStartFunctions();
68+
func(time);
69+
HYD.runFrameEndFunctions();
70+
}
71+
target.apply(thisArg, [funcNew]);
72+
}
73+
});
74+
window.requestAnimationFrame = proxy;
75+
HYD.hydInstrument( _GL2GPU_CONFIG["cmbMode"], _GL2GPU_CONFIG["replayDelay"], _GL2GPU_CONFIG["uniformBatchSize"] );
76+
```
77+
78+
Extension 的实现中还使用 sessionStorage 来保存GL2GPU开启状态。保存的key名称为 'HYD_LOAD_KEY',可选项有 'on' 和 'off'。这样可以实现点击浏览器插件栏插件来开启/关闭GL2GPU。
79+
80+
`_GL2GPU_CONFIG` 定义了运行配置。
81+
82+
- `cmbMode` 表示优化开关,可选项有:
83+
- "cmb": cache + merge uniform + bundle
84+
- "c1mb": cache (without layer-2 cache) + merge uniform + bundle
85+
- "mb": merge uniform + bundle
86+
- "m": merge uniform
87+
- "cm": cache + merge uniform
88+
- `replayDelay` 表示等待多少毫秒之后开启 replay mode,$-1$ 表示关闭replay mode
89+
- `sessionStorage` 表示 merged uniform size
90+
91+
## 关于 chrome extension
92+
93+
目录为 `/extension`。插件旨在将目录下的 `inject.js` 注入当前页面。
94+
95+
修改 `inject.js` 然后在 chrome://extensions 里面刷新插件即可加载最新的配置。
96+
97+
## 关于 frame times
98+
99+
现在三个 demo 都包含一段代码,可以记录 frameTimes. 记录原理如下:
100+
101+
```javascript
102+
var frameTimes = [];
103+
function render() {
104+
const startTime = performance.now();
105+
// render logic
106+
const endTime = performance.now();
107+
frameTimes.push(endTime - startTime);
108+
}
109+
110+
requestAnimationFrame(render);
111+
```
112+
113+
为了方便导出,我设置了获取 2000 个 frameTime 后保存 `frameTimes` 为json并下载。
114+
115+
## Demo
116+
117+
- https://serverless.pku.edu.cn/gl2gpu/aquarium/?numFish=100
118+
- https://serverless.pku.edu.cn/gl2gpu/sprites/?numSprites=100
119+
- https://serverless.pku.edu.cn/gl2gpu/motionmark/?numTriangles=100
120+
121+
# 二次开发
122+
123+
## Shader
124+
125+
WebGL 的 shader 需要在编译项目前单独翻译。翻译shader将得到一个json文件(`src/componenets/shaders/shaders_info.json`)。我们的翻译器会在 `shaderDB.ts` 中import这个 `shaders_info.json`
126+
127+
目录 `src/componenets/shaders` 存放着与shader有关的所有代码。每个demo的shader代码在`src/componenets/shaders/<demo名称>`目录下。可以用 Python 3 执行 `src/componenets/shaders/glsl_to_bindings.py` 来自动生成 `src/componenets/shaders/shaders_info.json`
128+
129+
> **由于变量alignment的问题,WebGL的shader无法“一对一”地翻译到WebGPU。**对于同一个 WebGL shader,可能有多种不同的WebGPU shader与之对应。这是因为GLSL(WebGL的shader语法)在开头不需要声明所有的全局变量,而WGSL(WebGPU的shader语法)则需要。不同的vertex和fragment的组合造成了翻译得到的WGSL的不一致。
130+
131+
> 我们在翻译器的运行中解决这个 alignment 的问题。
132+
133+
为了让 `glsl_to_bindings.py` 自动生成shader代码需要在编写每个项目的shader代码时注意以下两点:
134+
135+
1. 把所有的uniform变量用 `_hyd_uniforms_` 给打包起来;
136+
2. 一个WebGL的texture uniform在WGSL中需要用两个bindgroup的变量表示。分别是sampler和texture。命名格式形如 xxxS, xxxT,其中xxx为GLSL中texture的变量名。
137+
138+
编写shader时只需保留运算逻辑,不需要声明 uniform binding group 和 storage binding group. 可以在 `hydProgram.ts``linkProgram()` 中打印alignment完成后的WGSL shader。
139+
140+
<!--
141+
# Challenge
142+
143+
- 判断每个request animation frame的开始,frame和`clear()`的不对应。
144+
- 不然createView耗时长。
145+
- **shader的转换**和uniform binding的对齐。
146+
- `mat4` can be a type of a vertex buffer. `in mat4 matrix`.
147+
- 一些小的uniform buffer可能不符合`minBindingSize`的要求。
148+
- WebGPU不支持`gl_PointSize`。
149+
- **mipmaps**.
150+
- WebGPU texture 的实现中 sampler (texture state) 和 内存 (texture data) 的分离
151+
- `gl.LUMINANCE`
152+
- ==坐标变换==
153+
- uniform buffer performance?
154+
- 不支持 $\mathit{type}$ 为`gl.UNSIGNED_BYTE`的`drawElements`.
155+
- `instanceof`
156+
- WebGPU: texture, viewDimension / WebGL: `bindTexture()`
157+
- WebGL的bindTexture不能bind两次!
158+
- stencil attachments
159+
- 合并uniform buffer?
160+
- https://stackoverflow.com/questions/33589784/ssbo-as-bigger-ubo
161+
- https://community.khronos.org/t/uniform-buffer-memory-barriers/6777
162+
- cache开销!
163+
164+
# To-do
165+
166+
## Functionality
167+
168+
### usability
169+
170+
- [ ] [做成插件](https://stackoverflow.com/questions/19191679/chrome-extension-inject-js-before-page-load)
171+
172+
### global state
173+
174+
- [x] Vertex Array Object
175+
- [x] Texture
176+
- [x] test5.html
177+
- [x] shadow mapping
178+
- [x] **framebuffer, renderbuffer (多pipeline?)**
179+
- [x] depth
180+
- [x] stencil
181+
- [x] blend
182+
- [x] cullFace
183+
- [x] CubeMap
184+
- [x] threejs example
185+
- [x] scissor box
186+
- [ ] dithering
187+
- [ ] buffer writemasks
188+
- [ ] multisample?
189+
- [ ] `gl.vertexAttrib4f()`
190+
- [ ] ~~生成 `BindGroupLayout`~~
191+
- [ ] **`RenderPass` Cache**
192+
- [x] fuse `uniforms` into one struct
193+
- [alignment](https://www.w3.org/TR/WGSL/#alignment-and-size)
194+
195+
### shader
196+
197+
- [ ] GLSL -> WGSL
198+
- [ ] uniform & attribute location
199+
200+
## JS-tricks
201+
202+
- [ ] `instanceof`
203+
- [ ] fake `device.queue`
204+
205+
## Performance
206+
207+
- [ ] cache CommandEncoder&Pipeline&BindGroup&VertexState&VertexBufferLayout?TextureView?
208+
- [ ] performance of `writeUniform, draw, writeUniform, draw` ...
209+
210+
211+
# 优化方向
212+
213+
- `BindGroup` 重用
214+
- `BindGroupLayout` 重用
215+
- 根据更改频率对资源进行分组
216+
- `BindGroup(0)` 放更改频率最低的
217+
-->

extension/LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2021 SimGus
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

extension/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
https://developer.chrome.com/docs/extensions/reference/action/#injecting-a-content-script-on-click

extension/background.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//_______________________________EXTENSION POLYFILL_____________________________________
2+
function sendMessage(message) {
3+
chrome.tabs.query({ active: true, currentWindow: true }, function(tabs) {
4+
chrome.tabs.sendMessage(tabs[0].id, message);
5+
});
6+
};
7+
8+
function listenForMessage(callback) {
9+
chrome.runtime.onMessage.addListener(callback);
10+
};
11+
//_____________________________________________________________________________________
12+
13+
chrome.action.onClicked.addListener(function (tab) {
14+
sendMessage({ action: "hydInjectClick" });
15+
});
16+
17+
listenForMessage(function(request, sender, sendResponse) {
18+
var frameId;
19+
if (sender.frameId) {
20+
frameId = sender.frameId;
21+
}
22+
else if (request.uniqueId) {
23+
frameId = request.uniqueId;
24+
}
25+
else {
26+
frameId = sender.id;
27+
}
28+
29+
if (request.present === 2) {
30+
chrome.action.setIcon({tabId: sender.tab.id, path: {
31+
"16": "logo/logo-16.png",
32+
"48": "logo/logo-48.png",
33+
"128": "logo/logo-128.png"
34+
}});
35+
}
36+
else if (request.present === 0) {
37+
chrome.action.setIcon({tabId: sender.tab.id, path: {
38+
"16": "logo/logo-16-grey.png",
39+
"48": "logo/logo-48-grey.png",
40+
"128": "logo/logo-128-grey.png"
41+
}});
42+
}
43+
44+
frameId += "";
45+
});

0 commit comments

Comments
 (0)