let colors = {}; let rasterized = {}; 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]; } const r = Math.floor(Math.random() * 155); const g = Math.floor(Math.random() * 155); const b = Math.floor(Math.random() * 155); colors[stage_name] = [ 100 + r, 100 + g, 100 + b ]; return colors[stage_name]; } function rasterize_and_pack(text, cycles) { // TODO: handle texture is full or stuff don't fit (unlikely) const key = text + '@' + cycles; if (key in rasterized) { return rasterized[key]; } let cycles_total_padding = (cycles - 1) * config.padding; let bonus_cells = Math.ceil(cycles_total_padding / config.w); const tiles_needed = 1; // cycles - 1 + 1 + bonus_cells; // stage name + count cycles from one if (tiles_needed > config.raster_texture_size / config.w - raster_tile.x) { raster_tile.x = 0; raster_tile.y += 1; } 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; /* raster_tile.x += cycles + bonus_cells; if (raster_tile.x === config.raster_texture_size / config.w) { raster_tile.x = 0; raster_tile.y += 1; } */ rasterized[key] = [u, v]; 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) { r = Math.max(50, r - 50); g = Math.max(50, g - 50); b = Math.max(50, b - 50); a = 100; } 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]; 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 (false) { 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) { 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; }