优化 worker 的负载函数 | 支持对于 parameter 的渲染

This commit is contained in:
锦恢 2024-05-13 02:51:27 +08:00
parent a8ae1d6608
commit 703ba8a58c
20 changed files with 165 additions and 248 deletions

1
.gitignore vendored
View File

@ -21,3 +21,4 @@ pnpm-debug.log*
*.njsproj
*.sln
*.sw?
*.vcd

View File

@ -1,6 +1,6 @@
<mxfile host="65bd71144e">
<diagram id="fareUikBvdjO0hJmng89" name="makeBitVertex 原理图">
<mxGraphModel dx="1529" dy="929" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="0" pageScale="1" pageWidth="827" pageHeight="1169" math="1" shadow="0">
<mxGraphModel dx="2008" dy="1429" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="0" pageScale="1" pageWidth="827" pageHeight="1169" math="1" shadow="0">
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
@ -570,7 +570,7 @@
</mxGraphModel>
</diagram>
<diagram id="ldzhMOmdS79g5s7hsVNb" name="makeVecVertex 原理图">
<mxGraphModel dx="-10" dy="250" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="0" pageScale="1" pageWidth="827" pageHeight="1169" math="1" shadow="0">
<mxGraphModel dx="245" dy="529" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="0" pageScale="1" pageWidth="827" pageHeight="1169" math="1" shadow="0">
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>

View File

@ -15,14 +15,13 @@
<script>
window.readVcdFile = async () => {
const response = await fetch('test.vcd');
const response = await fetch('pe_tb.vcd');
const blob = await response.blob();
const reader = new FileReader();
return new Promise((resolve, reject) => {
reader.onload = event => {
const fileContent = event.target.result;
const unintarray = new Uint8Array(fileContent);
resolve(unintarray);
const arrayBuffer = event.target.result;
resolve(arrayBuffer);
};
reader.readAsArrayBuffer(blob);
});

File diff suppressed because one or more lines are too long

Binary file not shown.

9
public/worker.js Normal file
View File

@ -0,0 +1,9 @@
importScripts('vcd.js');
self.onmessage = async event => {
const arrayBuffer = event.data;
const vcdstream = await makeVcdStream();
vcdstream.consume(arrayBuffer);
const info = vcdstream.getBasicInfo();
self.postMessage(info);
}

View File

@ -16,14 +16,19 @@
<script setup>
import { onMounted, reactive, watch } from 'vue';
import { getVcdStream, numberOrString, gcd, normaliseUsingGCD, parseTimescale } from '@/hook/utils';
import { emitter, globalLookup, globalSetting, signalValues } from '@/hook/global';
import { useI18n } from 'vue-i18n';
import { ElLoading } from 'element-plus';
import { emitter, globalLookup, globalSetting } from '@/hook/global';
import { makeWaveView } from '@/hook/render';
import Sidebar from '@/components/sidebar.vue';
import RightNav from '@/components/right-nav.vue';
import MainRender from '@/components/render';
const { t } = useI18n();
// globalSetting localStorage
watch(
() => globalSetting,
@ -39,6 +44,11 @@ const VcdInfo = reactive({
});
onMounted(async () => {
const loading = new ElLoading.service({
lock: true,
text: t('loading'),
background: 'rgba(0, 0, 0, 0.7)'
});
//
document.body.style.setProperty('--el-color-primary', 'var(--main-color)');
document.body.style.setProperty('--el-color-primary-light-9', 'var(--main-color)');
@ -72,71 +82,56 @@ onMounted(async () => {
}
// vcd
const uint8array = await window.readVcdFile();
const vcdstream = await getVcdStream();
const arrayBuffer = await window.readVcdFile();
let tgcd;
// 使 vcdstream any
// https://github.com/wavedrom/vcd vcd-pipe-deso.js 58
//
vcdstream.change.any((id, time, cmd, value, mask) => {
const time53 = Number(time);
tgcd = gcd(tgcd, time53);
signalValues[id] = signalValues[id] || { kind: '', wave: [] };
const worker = new Worker('worker.js', {
name: 'vcd-stream',
type: 'classic'
});
if (cmd >= 14 && cmd <= 28) {
signalValues[id].kind = 'bit';
signalValues[id].wave.push([time53, cmd - 14]);
} else {
signalValues[id].kind = 'vec';
const point = [time53, numberOrString(value)];
if (mask !== 0n) {
point.push(numberOrString(mask));
worker.postMessage(arrayBuffer, [arrayBuffer]);
worker.addEventListener('message', event => {
const workerVars = event.data;
console.log(workerVars);
const vcdInfo = workerVars.vcdInfo;
const signalValues = workerVars.signalValues;
for (const topModule of vcdInfo.wires.body) {
VcdInfo.topModules.push(topModule);
}
globalLookup.status = vcdInfo.status;
globalLookup.version = vcdInfo.version;
globalLookup.timescale = vcdInfo.timescale;
globalLookup.date = vcdInfo.date;
globalLookup.t0 = vcdInfo.t0 || 0;
globalLookup.tgcd = workerVars.tgcd;
globalLookup.time = workerVars.time;
globalLookup.chango = signalValues;
makeWaveView();
console.log(signalValues['*']);
// console.log('duration time', globalLookup.time);
emitter.emit('meta-ready', null);
//
//
if (VcdInfo.topModules.length > 0) {
const defaultMod = VcdInfo.topModules[0];
const wires = defaultMod.body.filter(mod => mod.link);
emitter.emit('tree-view', wires);
// 便
for (const mod of VcdInfo.topModules) {
globalLookup.topModules.push(mod);
}
signalValues[id].wave.push(point);
}
loading.close();
worker.terminate();
});
vcdstream.on('$enddefinitions', () => {
});
const maxChunkLength = 1 << 17;
for (let i = 0; i < uint8array.length; i += maxChunkLength) {
const piece = uint8array.slice(i, i + maxChunkLength);
vcdstream.write(piece);
}
for (const topModule of vcdstream.info.wires.body) {
VcdInfo.topModules.push(topModule);
}
globalLookup.status = vcdstream.info.status;
globalLookup.version = vcdstream.info.version;
globalLookup.timescale = parseTimescale(vcdstream.info.timescale);
globalLookup.date = vcdstream.info.date;
globalLookup.t0 = vcdstream.info.t0 || 0;
globalLookup.tgcd = tgcd;
globalLookup.time = Number(vcdstream.getTime());
globalLookup.chango = signalValues;
normaliseUsingGCD(globalLookup, signalValues);
makeWaveView();
// console.log('duration time', globalLookup.time);
emitter.emit('meta-ready', null);
//
//
if (VcdInfo.topModules.length > 0) {
const defaultMod = VcdInfo.topModules[0];
const wires = defaultMod.body.filter(mod => mod.link);
emitter.emit('tree-view', wires);
// 便
for (const mod of VcdInfo.topModules) {
globalLookup.topModules.push(mod);
}
}
});
</script>

View File

@ -56,6 +56,7 @@ export default {
.vcd-vline {
position: absolute;
transition: var(--animation-5s);
}
.vcd-view {
@ -64,10 +65,16 @@ export default {
bottom: var(--vcd-render-padding);
}
.vcd-hidden {
opacity: 0;
transition: var(--animation-5s);
}
.vcd-values {
position: absolute;
top: var(--vcd-render-padding);
bottom: var(--vcd-render-padding);
transition: var(--animation-5s);
}
.wd-waveql {

View File

@ -23,7 +23,6 @@
<script>
import { onMounted, reactive } from 'vue';
import { globalLookup, emitter } from '@/hook/global';
import { handleTimeScale } from '@/hook/utils';
import { wheelScale } from '@/hook/wheel';
export default {
@ -43,13 +42,6 @@ export default {
//
emitter.on('meta-ready', () => {
// const { scale, unit } = handleTimeScale(globalLookup.timescale);
// timeScaleManage.scale = scale;
// timeScaleManage.unit = unit;
// console.log(timeScaleManage.unit);
// const viewInfo = globalLookup.view;
});
// document.addEventListener('wheel', event => {

View File

@ -205,7 +205,6 @@ watch(() => wavecolor.currentOptionIndex, () => {
});
watch(() => wavecolor.colors, () => {
console.log('enter');
const colorString = wavecolor.colors[wavecolor.currentOptionIndex];
const rgba = rgba2WebglColor(colorString);
if (rgba !== undefined) {

View File

@ -94,7 +94,7 @@ const globalSetting = reactive({
HorizontalRollRatio: 1,
VerticalRollRario: 1,
minGridWidth: 300,
prerender: true,
prerender: false,
renderAnimation: false,
});
@ -119,20 +119,9 @@ if (storedSetting) {
}
// for (const key of Reflect.ownKeys(globalSetting)) {
// const value = localStorageGetItem(key);
// if (value !== undefined && value !== null) {
// globalSetting[key] = value;
// }
// }
const signalValues = {};
export {
emitter,
globalLookup,
globalSetting,
globalStyle,
signalValues
globalStyle
};

View File

@ -1,4 +1,4 @@
import { globalLookup, globalSetting, signalValues } from "./global";
import { globalLookup, globalSetting } from "./global";
import { domContainer, pluginRenderTimeGrid, pluginRenderValues, mountTree,
genOnWheel, genKeyHandler, keyEvent } from './wave-view';
@ -78,6 +78,8 @@ function toggleRender(signal) {
} else {
globalLookup.currentWires.add(signal);
const signalItem = globalLookup.chango[signal.link];
console.log(signalItem, signal.link);
const { wave, kind } = signalItem;
const time = globalLookup.currentTime;
globalLookup.currentSignalValues[signal.link] = findCurrentSignalValue(kind, wave, time);

View File

@ -196,100 +196,6 @@ function findCurrentSignalValue(kind, wave, time) {
return value;
}
/**
*
* @param {string} timescale
* @return {{
* scale: number,
* unit: string
* }}
*/
function handleTimeScale(timescale) {
const match = timescale.match(/^(\d+)(.*)$/);
if (match.length === 3) {
const scale = parseInt(match[1]);
const unit = match[2];
return { scale, unit };
} else {
console.log('Error: fail to parse timescale ' + timescale);
return { scale: null, unit: null };
}
}
const MAX_SAFE_INTEGER = BigInt(Number.MAX_SAFE_INTEGER);
/**
*
* @param {string} timescale
* @returns {string}
*/
function parseTimescale(timescale) {
if (typeof timescale !== 'string') {
return;
}
const str1 = timescale.trim();
const m = str1.match(/^(\d+)\s*(\w+)$/);
const res1 = ({ 1: 0, 10: 1, 100: 2 })[m[1]];
const res2 = ({ s: 0, ms: -3, us: -6, ns: -9, ps: -12, fs: -15 })[m[2]];
return res1 + res2;
}
/**
*
* @param {BigInt} val
* @returns {string | number}
*/
function numberOrString(val) {
if (val < MAX_SAFE_INTEGER) {
return Number(val);
}
return '0x' + val.toString(16);
}
/**
*
* @param {number} a
* @param {number} b
* @returns {number}
*/
function gcd(a, b) {
if (a === undefined) {
return b;
}
let r;
while (b !== 0) {
r = a % b;
a = b;
b = r;
}
return (a < 0) ? -a : a;
}
function normaliseUsingGCD(globalLookup, signalValues) {
// const { tgcd, chango } = o;
const tgcd = globalLookup.tgcd;
// 使用全局最大公约数缩小时间倍率
globalLookup.t0 /= tgcd;
globalLookup.time /= tgcd;
for (const id of Reflect.ownKeys(signalValues)) {
// point[0] 是当前这个点的时间点
signalValues[id].wave.map(point => { point[0] /= tgcd });
}
const exp = Math.log10(tgcd) | 0;
if (exp > 0) {
const scale = Math.pow(10, exp);
const scaleGcd = tgcd / scale;
if (scaleGcd === (scaleGcd | 0)) {
globalLookup.tgcd = scaleGcd;
globalLookup.timescale += exp;
}
}
}
const scopes = new Set(['begin', 'fork', 'function', 'module', 'task']);
const variables = new Set(['event', 'integer', 'parameter', 'real', 'realtime', 'reg', 'supply0',
@ -357,17 +263,12 @@ export {
getVcdStream,
debounceWrapper,
makeSearchResultItem,
handleTimeScale,
isScope,
isVariable,
makeIconClass,
scopes,
variables,
parseTimescale,
numberOrString,
gcd,
findCurrentSignalValue,
normaliseUsingGCD,
updateWireCurrentValue,
predefinedColors,
webglColor2rgba,

View File

@ -169,6 +169,7 @@ const domContainer = (obj) => {
setTime(pstate, deso.timeOpt.value);
}
const waveRender = new WebGL2WaveRender(elo, deso, pstate, obj.renderPlugins);
deso.render = waveRender.render.bind(waveRender);
deso.waveRender = waveRender;
@ -187,7 +188,7 @@ const domContainer = (obj) => {
// console.log('resizeObserver', width, height);
resizeHandler(width, height);
}
deso.render();
deso.render({ type: 'action' });
});
resizeObserver.observe(document.body);

View File

@ -1,9 +1,9 @@
const formatTime = (t, expo) => {
const prefixes = ['T', 'G', 'M', 'k', '', 'm', 'µ', 'n', 'p', 'f', 'a', 'z', 'y'];
const ts1 = 14 - expo;
const prefix = prefixes[(ts1 / 3) |0];
const mult = ([100, 10, 1])[ts1 % 3];
return (t * mult).toLocaleString() + ' ' + prefix + 's';
const prefixes = ['T', 'G', 'M', 'k', '', 'm', 'µ', 'n', 'p', 'f', 'a', 'z', 'y'];
const ts1 = 14 - expo;
const prefix = prefixes[(ts1 / 3) | 0];
const mult = ([100, 10, 1])[ts1 % 3];
return (t * mult).toLocaleString() + ' ' + prefix + 's';
};
export default formatTime;

View File

@ -1,28 +1,28 @@
const { keyName } = require('w3c-keyname');
const executeKeyHandler = (key, keyEvent, pstate, cm) => {
return (keyEvent[key] || keyEvent.nop).fn(pstate, cm);
return (keyEvent[key] || keyEvent.nop).fn(pstate, cm);
};
const genKeyHandler = (div, pstate, deso, cm, keyEvent, plugins) => {
return event => {
return event => {
const modifier = (
(event.ctrlKey ? 'Ctrl+' : '') +
(event.shiftKey ? 'Shift+' : '') +
(event.altKey ? 'Alt+' : '')
);
// const key = modifier + event.key;
const key = modifier + keyName(event);
const modifier = (
(event.ctrlKey ? 'Ctrl+' : '') +
(event.shiftKey ? 'Shift+' : '') +
(event.altKey ? 'Alt+' : '')
);
// const key = modifier + event.key;
const key = modifier + keyName(event);
if (executeKeyHandler(key, keyEvent, pstate, cm)) {
event.stopPropagation();
if (plugins != undefined) {
plugins.map(fn => fn(key, event));
}
deso.render();
}
};
if (executeKeyHandler(key, keyEvent, pstate, cm)) {
event.stopPropagation();
if (plugins != undefined) {
plugins.map(fn => fn(key, event));
}
deso.render();
}
};
};
export default {

View File

@ -9,7 +9,7 @@ const genOnWheel = (element, pstate, deso, keyEvent, plugins) =>
if (plugins != undefined) {
plugins.map(fn => fn(key, event));
}
deso.render();
deso.render({ type: 'action' });
}
event.preventDefault();
} else if (event.shiftKey) {
@ -18,7 +18,7 @@ const genOnWheel = (element, pstate, deso, keyEvent, plugins) =>
if (plugins != undefined) {
plugins.map(fn => fn(key, event));
}
deso.render();
deso.render({ type: 'action' });
}
event.preventDefault();
} else if (deltaX !== 0 && deltaY === 0) {
@ -27,7 +27,7 @@ const genOnWheel = (element, pstate, deso, keyEvent, plugins) =>
if (plugins != undefined) {
plugins.map(fn => fn(key, event));
}
deso.render();
deso.render({ type: 'action' });
}
event.preventDefault();
} else if (deltaX === 0 && deltaY !== 0) {
@ -36,7 +36,7 @@ const genOnWheel = (element, pstate, deso, keyEvent, plugins) =>
if (plugins != undefined) {
plugins.map(fn => fn(key, event));
}
deso.render();
deso.render({ type: 'action' });
}
event.preventDefault();
}

View File

@ -14,10 +14,11 @@ const xScaleLevels = {
5: 10 / 4
};
// TODO: 优化横向滚动体验
const xOffsetLevel = {
1: 5,
2: 4,
3: 3,
1: 500,
2: 20,
3: 5,
4: 1,
5: 0.5
};

View File

@ -1,8 +1,4 @@
import { ElLoading } from 'element-plus';
import { globalSetting, globalStyle } from '../global';
import i18n from '../../i18n';
const { t } = i18n.global;
import { gl_Colors, gl_Shifts, gl_Shifts_for_bar, gl_Shifts_map, gl_WidthShifts, barShift, getRatio, screenHeightPixel } from './render-utils.js';
import { vertexShader, fragmentShader } from './render-shader.js';
@ -49,12 +45,6 @@ class WebGL2WaveRender {
* @param { Array } plugins
*/
constructor(elements, globalLookup, pstate, plugins) {
const loading = ElLoading.service({
lock: true,
text: t('loading'),
background: 'rgba(0, 0, 0, 0.7)'
});
const canvas = document.createElement('canvas');
elements.view.replaceChildren(canvas);
@ -76,8 +66,6 @@ class WebGL2WaveRender {
this.maskVerticesMap = maskVerticesMap;
this.initData();
this.animationHandler = undefined;
loading.close();
}
/**
@ -156,6 +144,9 @@ class WebGL2WaveRender {
} else if (kind === 'vec') {
const { lineVertices, maskVertices } = this.makeVecVertex(wave, time);
return { lineVertices, maskVertices };
} else if (kind === '') {
const { lineVertices, maskVertices } = this.makeVecVertex(wave, time);
return { lineVertices, maskVertices };
}
return {
lineVertices: undefined,
@ -217,6 +208,8 @@ class WebGL2WaveRender {
}
}
}
return 0;
}
/**
@ -330,6 +323,11 @@ class WebGL2WaveRender {
const y1Index = gl_Shifts_map.get(p1.y);
const wsIndex = this.makeWidthShiftIndexByPoints(p0, p1, p2);
if (wsIndex === undefined) {
console.log(p0, p1, p2);
}
lineVertices.push(
p1.x, y1Index, p1.color, wsIndex,
p1.x, y1Index, p1.color, (wsIndex + 4) % 8
@ -377,12 +375,11 @@ class WebGL2WaveRender {
}
}
// if (debug) {
// console.log(perspectivePoints);
// console.log(pointNum);
// console.log(lineVertices);
// }
if (debug) {
console.log(perspectivePoints);
console.log(pointNum);
console.log(lineVertices);
}
return {
lineVertices : new Uint32Array(lineVertices),
@ -484,6 +481,7 @@ class WebGL2WaveRender {
this.lineVerticesMap.set(id, lineVertices);
this.maskVerticesMap.set(id, maskVertices);
}
const lineVertices = this.lineVerticesMap.get(id);
const maskVertices = this.maskVerticesMap.get(id);
@ -559,7 +557,16 @@ class WebGL2WaveRender {
this.render();
}
render() {
/**
*
* @param {{
* type: 'common' | 'action'
* } | undefined} renderConfig
*/
render(renderConfig) {
renderConfig = renderConfig || { type: 'common' };
const needHiddenAnimation = globalSetting.renderAnimation && renderConfig.type === 'action';
if (this.animationHandler !== undefined) {
cancelAnimationFrame(this.animationHandler);
}
@ -595,8 +602,16 @@ class WebGL2WaveRender {
let startTime = undefined;
// 默认执行一个 300 ms 的动画
const animationDuration = 300;
if (needHiddenAnimation) {
this.elements.grid.classList.add('vcd-hidden');
this.elements.values.classList.add('vcd-hidden');
}
let animationHandler = this.animationHandler = requestAnimationFrame(drawWaves);
const _this = this;
function linearAnimation(delta, oldVal, newVal) {
return (1 - delta) * oldVal + delta * newVal;
}
@ -630,8 +645,8 @@ class WebGL2WaveRender {
const id = signal.link;
const wave = globalLookup.chango[id].wave;
// this.makeBitVertex(wave, globalLookup.time, true);
// this.makeVecVertex(wave, globalLookup.time, true);
// _this.makeBitVertex(wave, globalLookup.time, true);
// _this.makeVecVertex(wave, globalLookup.time, true);
const signalItem = globalLookup.chango[id];
if (!signalItem) {
@ -644,7 +659,7 @@ class WebGL2WaveRender {
// 根据 lineVao 进行绘制
if (lineVerticesMap.get(id) === undefined) {
this.initVertice(id);
_this.initVertice(id);
}
const lineVertices = lineVerticesMap.get(id);
const maskVertices = maskVerticesMap.get(id);
@ -689,6 +704,11 @@ class WebGL2WaveRender {
pstate.oldXScale = pstate.xScale;
pstate.oldYStep = pstate.yStep;
pstate.oldYDuty = pstate.yDuty;
if (needHiddenAnimation) {
_this.elements.grid.classList.remove('vcd-hidden');
_this.elements.values.classList.remove('vcd-hidden');
}
return;
}
}

View File

@ -59,8 +59,9 @@ window.onload = async () => {
gl.clear(gl.COLOR_BUFFER_BIT);
const points = [
0, -0.5,
0.5, -0.5,
0, 0,
0.5, 0,
0.7, 0
];
drawMask(gl, program, points, { width: 0.06 });