kanat is too fat
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

263 lines
6.9 KiB

let colors = {};
let rasterized = {};
// https://stackoverflow.com/a/17243070
function hsv_to_rgb(h, s, v) {
let r, g, b;
const i = Math.floor(h * 6);
const f = h * 6 - i;
const p = v * (1 - s);
const q = v * (1 - f * s);
const t = v * (1 - (1 - f) * s);
switch (i % 6) {
case 0: r = v, g = t, b = p; break;
case 1: r = q, g = v, b = p; break;
case 2: r = p, g = v, b = t; break;
case 3: r = p, g = q, b = v; break;
case 4: r = t, g = p, b = v; break;
case 5: r = v, g = p, b = q; break;
}
return [
Math.round(r * 255),
Math.round(g * 255),
Math.round(b * 255)
];
}
function get_color(stage_name) {
if (stage_name in config.predefined_colors) {
return config.predefined_colors[stage_name];
}
if (stage_name in colors) {
return colors[stage_name];
}
colors[stage_name] = hsv_to_rgb(Math.random(), 0.56, 0.56);
return colors[stage_name];
}
function rasterize_and_pack(text, cycles) {
// TODO: handle texture is full or stuff don't fit (unlikely)
const key = text;
if (key in rasterized) {
return rasterized[key];
}
const u = raster_tile.x * config.w / config.raster_texture_size;
const v = raster_tile.y * config.h / config.raster_texture_size;
rasterize(text);
gl.bindTexture(gl.TEXTURE_2D, textures['raster']);
gl.texSubImage2D(gl.TEXTURE_2D, 0,
raster_tile.x * config.w, raster_tile.y * config.h,
config.w, config.h,
gl.RGBA, gl.UNSIGNED_BYTE,
c2d.canvas
);
raster_tile.x += 1;
if (raster_tile.x === config.raster_texture_size / config.w) {
raster_tile.x = 0;
raster_tile.y += 1;
}
rasterized[key] = [u, v];
if (cycles > 1) {
gl.bindTexture(gl.TEXTURE_2D, textures['numbers']);
for (let i = numbers_rasterized + 1; i <= cycles; ++i) {
const u = number_tile.x * config.w / config.raster_texture_size;
const v = number_tile.y * config.h / config.raster_texture_size;
rasterize(i);
gl.texSubImage2D(gl.TEXTURE_2D, 0,
number_tile.x * config.w, number_tile.y * config.h,
config.w, config.h,
gl.RGBA, gl.UNSIGNED_BYTE,
c2d.canvas
);
number_tile.x += 1;
if (number_tile.x === config.raster_texture_size / config.w) {
number_tile.x = 0;
number_tile.y += 1;
}
rasterized[i] = [u, v];
}
if (cycles > numbers_rasterized) {
numbers_rasterized = cycles;
}
}
return [u, v];
}
function pack_instruction(instruction, positions, sizes, colors, uvs, starts, y) {
starts.push(positions.length);
for (let i = 0; i < instruction.lanes['0'].length; ++i) {
const stage = instruction.lanes['0'][i];
let stage_cycles;
if (i < instruction.lanes['0'].length - 1) {
const next_stage = instruction.lanes['0'][i + 1];
stage_cycles = next_stage.c - stage.c;
} else {
stage_cycles = instruction.retcyc - stage.c;
}
let [r, g, b] = get_color(stage.name);
let a = 255;
if (!instruction.retired) {
a = 80;
}
const [u, v] = rasterize_and_pack(stage.name, stage_cycles);
sizes.push(stage_cycles * config.w + (stage_cycles - 1) * config.padding, 1 * config.h);
positions.push(config.w * stage.c + config.padding * (stage.c - 1), config.h * y + config.padding * (y - 1));
colors.push(r, g, b, a);
uvs.push(u, v);
}
return instruction.lanes['0'].length;
}
function generate(trace_id) {
const before = performance.now();
const result = {
'count': 0,
};
const positions = [];
const sizes = [];
const colors = [];
const uvs = [];
const starts = [];
let instructions = {};
if (trace_id in traces) {
instructions = traces[trace_id].raw;
}
let y = 0;
for (let i = 0; i < instructions.length; ++i) {
const instruction = instructions[i];
// TODO: make all quads same size, abuse this fact
result.count += pack_instruction(instruction, positions, sizes, colors, uvs, starts, y);
if (config.limit > 0 && result.count >= config.limit) {
break;
}
++y;
}
starts.push(positions.length);
if (config.show_texture) {
result.pos = new Float32Array([0, 0]);
result.size = new Float32Array([config.raster_texture_size, config.raster_texture_size]);
result.color = new Uint8Array([0, 0, 0, 255]);
result.uv = new Float32Array([0, 0]);
result.count = 1;
result.trace_id = trace_id;
result.uploaded = false;
} else {
result.pos = new Float32Array(positions);
result.size = new Float32Array(sizes);
result.color = new Uint8Array(colors);
result.uv = new Float32Array(uvs);
result.trace_id = trace_id;
result.uploaded = false;
result.start = new Int32Array(starts);
}
const after = performance.now();
console.log(`Generated geometry in ${Math.round(after - before)}ms`);
return result;
}
function clip(quads) {
if (config.show_texture) {
return quads;
}
const tl = screen_to_canvas({'x': 0, 'y': 0});
const br = screen_to_canvas({'x': 0, 'y': canvas.height});
const x1 = tl.x;
const y1 = tl.y;
const x2 = br.x;
const y2 = br.y;
const result = {
'count': 0,
};
if (quads.count === 0) {
return result;
}
let i0 = -1;
let i1 = -1;
for (let i = 0; i < quads.start.length - 1; ++i) {
const index = quads.start[i];
const next = quads.start[i + 1];
const left = quads.pos[index];
const top = quads.pos[index + 1];
const bottom = top + quads.size[index + 1];
const right = quads.pos[next - 2] + quads.size[next - 2];
if (bottom < y1) {
if (i < quads.start.length / 2 - 2) {
const index_ahead = quads.start[i * 2];
const top_ahead = quads.pos[index_ahead + 1];
const bottom_ahead = top_ahead + quads.size[index_ahead + 1];
if (bottom_ahead < y1) {
i *= 2;
continue;
}
}
}
if (bottom < y1 || right < x1) {
continue;
}
if (top > y2) {
i1 = quads.start[i + 1];
break;
}
if (i0 === -1) {
i0 = index;
}
}
result.pos = quads.pos.subarray(i0, i1);
result.size = quads.size.subarray(i0, i1);
result.color = quads.color.subarray(i0 * 2, i1 * 2);
result.uv = quads.uv.subarray(i0, i1);
result.count = (i1 - i0) / 2;
result.uploaded = false;
return result;
}